schema.py 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256
  1. # -*- coding: utf-8 -*-
  2. #
  3. # QAPI schema internal representation
  4. #
  5. # Copyright (c) 2015-2019 Red Hat Inc.
  6. #
  7. # Authors:
  8. # Markus Armbruster <armbru@redhat.com>
  9. # Eric Blake <eblake@redhat.com>
  10. # Marc-André Lureau <marcandre.lureau@redhat.com>
  11. #
  12. # This work is licensed under the terms of the GNU GPL, version 2.
  13. # See the COPYING file in the top-level directory.
  14. # pylint: disable=too-many-lines
  15. # TODO catching name collisions in generated code would be nice
  16. from collections import OrderedDict
  17. import os
  18. import re
  19. from typing import List, Optional
  20. from .common import (
  21. POINTER_SUFFIX,
  22. c_name,
  23. cgen_ifcond,
  24. docgen_ifcond,
  25. gen_endif,
  26. gen_if,
  27. )
  28. from .error import QAPIError, QAPISemError, QAPISourceError
  29. from .expr import check_exprs
  30. from .parser import QAPIExpression, QAPISchemaParser
  31. class QAPISchemaIfCond:
  32. def __init__(self, ifcond=None):
  33. self.ifcond = ifcond
  34. def _cgen(self):
  35. return cgen_ifcond(self.ifcond)
  36. def gen_if(self):
  37. return gen_if(self._cgen())
  38. def gen_endif(self):
  39. return gen_endif(self._cgen())
  40. def docgen(self):
  41. return docgen_ifcond(self.ifcond)
  42. def is_present(self):
  43. return bool(self.ifcond)
  44. class QAPISchemaEntity:
  45. """
  46. A schema entity.
  47. This is either a directive, such as include, or a definition.
  48. The latter uses sub-class `QAPISchemaDefinition`.
  49. """
  50. def __init__(self, info):
  51. self._module = None
  52. # For explicitly defined entities, info points to the (explicit)
  53. # definition. For builtins (and their arrays), info is None.
  54. # For implicitly defined entities, info points to a place that
  55. # triggered the implicit definition (there may be more than one
  56. # such place).
  57. self.info = info
  58. self._checked = False
  59. def __repr__(self):
  60. return "<%s at 0x%x>" % (type(self).__name__, id(self))
  61. def check(self, schema):
  62. # pylint: disable=unused-argument
  63. self._checked = True
  64. def connect_doc(self, doc=None):
  65. pass
  66. def _set_module(self, schema, info):
  67. assert self._checked
  68. fname = info.fname if info else QAPISchemaModule.BUILTIN_MODULE_NAME
  69. self._module = schema.module_by_fname(fname)
  70. self._module.add_entity(self)
  71. def set_module(self, schema):
  72. self._set_module(schema, self.info)
  73. def visit(self, visitor):
  74. # pylint: disable=unused-argument
  75. assert self._checked
  76. class QAPISchemaDefinition(QAPISchemaEntity):
  77. meta: Optional[str] = None
  78. def __init__(self, name: str, info, doc, ifcond=None, features=None):
  79. assert isinstance(name, str)
  80. super().__init__(info)
  81. for f in features or []:
  82. assert isinstance(f, QAPISchemaFeature)
  83. f.set_defined_in(name)
  84. self.name = name
  85. self.doc = doc
  86. self._ifcond = ifcond or QAPISchemaIfCond()
  87. self.features = features or []
  88. def __repr__(self):
  89. return "<%s:%s at 0x%x>" % (type(self).__name__, self.name,
  90. id(self))
  91. def c_name(self):
  92. return c_name(self.name)
  93. def check(self, schema):
  94. assert not self._checked
  95. super().check(schema)
  96. seen = {}
  97. for f in self.features:
  98. f.check_clash(self.info, seen)
  99. def connect_doc(self, doc=None):
  100. super().connect_doc(doc)
  101. doc = doc or self.doc
  102. if doc:
  103. for f in self.features:
  104. doc.connect_feature(f)
  105. @property
  106. def ifcond(self):
  107. assert self._checked
  108. return self._ifcond
  109. def is_implicit(self):
  110. return not self.info
  111. def describe(self):
  112. assert self.meta
  113. return "%s '%s'" % (self.meta, self.name)
  114. class QAPISchemaVisitor:
  115. def visit_begin(self, schema):
  116. pass
  117. def visit_end(self):
  118. pass
  119. def visit_module(self, name):
  120. pass
  121. def visit_needed(self, entity):
  122. # pylint: disable=unused-argument
  123. # Default to visiting everything
  124. return True
  125. def visit_include(self, name, info):
  126. pass
  127. def visit_builtin_type(self, name, info, json_type):
  128. pass
  129. def visit_enum_type(self, name, info, ifcond, features, members, prefix):
  130. pass
  131. def visit_array_type(self, name, info, ifcond, element_type):
  132. pass
  133. def visit_object_type(self, name, info, ifcond, features,
  134. base, members, variants):
  135. pass
  136. def visit_object_type_flat(self, name, info, ifcond, features,
  137. members, variants):
  138. pass
  139. def visit_alternate_type(self, name, info, ifcond, features, variants):
  140. pass
  141. def visit_command(self, name, info, ifcond, features,
  142. arg_type, ret_type, gen, success_response, boxed,
  143. allow_oob, allow_preconfig, coroutine):
  144. pass
  145. def visit_event(self, name, info, ifcond, features, arg_type, boxed):
  146. pass
  147. class QAPISchemaModule:
  148. BUILTIN_MODULE_NAME = './builtin'
  149. def __init__(self, name):
  150. self.name = name
  151. self._entity_list = []
  152. @staticmethod
  153. def is_system_module(name: str) -> bool:
  154. """
  155. System modules are internally defined modules.
  156. Their names start with the "./" prefix.
  157. """
  158. return name.startswith('./')
  159. @classmethod
  160. def is_user_module(cls, name: str) -> bool:
  161. """
  162. User modules are those defined by the user in qapi JSON files.
  163. They do not start with the "./" prefix.
  164. """
  165. return not cls.is_system_module(name)
  166. @classmethod
  167. def is_builtin_module(cls, name: str) -> bool:
  168. """
  169. The built-in module is a single System module for the built-in types.
  170. It is always "./builtin".
  171. """
  172. return name == cls.BUILTIN_MODULE_NAME
  173. def add_entity(self, ent):
  174. self._entity_list.append(ent)
  175. def visit(self, visitor):
  176. visitor.visit_module(self.name)
  177. for entity in self._entity_list:
  178. if visitor.visit_needed(entity):
  179. entity.visit(visitor)
  180. class QAPISchemaInclude(QAPISchemaEntity):
  181. def __init__(self, sub_module, info):
  182. super().__init__(info)
  183. self._sub_module = sub_module
  184. def visit(self, visitor):
  185. super().visit(visitor)
  186. visitor.visit_include(self._sub_module.name, self.info)
  187. class QAPISchemaType(QAPISchemaDefinition):
  188. # Return the C type for common use.
  189. # For the types we commonly box, this is a pointer type.
  190. def c_type(self):
  191. pass
  192. # Return the C type to be used in a parameter list.
  193. def c_param_type(self):
  194. return self.c_type()
  195. # Return the C type to be used where we suppress boxing.
  196. def c_unboxed_type(self):
  197. return self.c_type()
  198. def json_type(self):
  199. pass
  200. def alternate_qtype(self):
  201. json2qtype = {
  202. 'null': 'QTYPE_QNULL',
  203. 'string': 'QTYPE_QSTRING',
  204. 'number': 'QTYPE_QNUM',
  205. 'int': 'QTYPE_QNUM',
  206. 'boolean': 'QTYPE_QBOOL',
  207. 'array': 'QTYPE_QLIST',
  208. 'object': 'QTYPE_QDICT'
  209. }
  210. return json2qtype.get(self.json_type())
  211. def doc_type(self):
  212. if self.is_implicit():
  213. return None
  214. return self.name
  215. def need_has_if_optional(self):
  216. # When FOO is a pointer, has_FOO == !!FOO, i.e. has_FOO is redundant.
  217. # Except for arrays; see QAPISchemaArrayType.need_has_if_optional().
  218. return not self.c_type().endswith(POINTER_SUFFIX)
  219. def check(self, schema):
  220. super().check(schema)
  221. for feat in self.features:
  222. if feat.is_special():
  223. raise QAPISemError(
  224. self.info,
  225. f"feature '{feat.name}' is not supported for types")
  226. def describe(self):
  227. assert self.meta
  228. return "%s type '%s'" % (self.meta, self.name)
  229. class QAPISchemaBuiltinType(QAPISchemaType):
  230. meta = 'built-in'
  231. def __init__(self, name, json_type, c_type):
  232. super().__init__(name, None, None)
  233. assert not c_type or isinstance(c_type, str)
  234. assert json_type in ('string', 'number', 'int', 'boolean', 'null',
  235. 'value')
  236. self._json_type_name = json_type
  237. self._c_type_name = c_type
  238. def c_name(self):
  239. return self.name
  240. def c_type(self):
  241. return self._c_type_name
  242. def c_param_type(self):
  243. if self.name == 'str':
  244. return 'const ' + self._c_type_name
  245. return self._c_type_name
  246. def json_type(self):
  247. return self._json_type_name
  248. def doc_type(self):
  249. return self.json_type()
  250. def visit(self, visitor):
  251. super().visit(visitor)
  252. visitor.visit_builtin_type(self.name, self.info, self.json_type())
  253. class QAPISchemaEnumType(QAPISchemaType):
  254. meta = 'enum'
  255. def __init__(self, name, info, doc, ifcond, features, members, prefix):
  256. super().__init__(name, info, doc, ifcond, features)
  257. for m in members:
  258. assert isinstance(m, QAPISchemaEnumMember)
  259. m.set_defined_in(name)
  260. assert prefix is None or isinstance(prefix, str)
  261. self.members = members
  262. self.prefix = prefix
  263. def check(self, schema):
  264. super().check(schema)
  265. seen = {}
  266. for m in self.members:
  267. m.check_clash(self.info, seen)
  268. def connect_doc(self, doc=None):
  269. super().connect_doc(doc)
  270. doc = doc or self.doc
  271. for m in self.members:
  272. m.connect_doc(doc)
  273. def is_implicit(self):
  274. # See QAPISchema._def_predefineds()
  275. return self.name == 'QType'
  276. def c_type(self):
  277. return c_name(self.name)
  278. def member_names(self):
  279. return [m.name for m in self.members]
  280. def json_type(self):
  281. return 'string'
  282. def visit(self, visitor):
  283. super().visit(visitor)
  284. visitor.visit_enum_type(
  285. self.name, self.info, self.ifcond, self.features,
  286. self.members, self.prefix)
  287. class QAPISchemaArrayType(QAPISchemaType):
  288. meta = 'array'
  289. def __init__(self, name, info, element_type):
  290. super().__init__(name, info, None)
  291. assert isinstance(element_type, str)
  292. self._element_type_name = element_type
  293. self.element_type = None
  294. def need_has_if_optional(self):
  295. # When FOO is an array, we still need has_FOO to distinguish
  296. # absent (!has_FOO) from present and empty (has_FOO && !FOO).
  297. return True
  298. def check(self, schema):
  299. super().check(schema)
  300. self.element_type = schema.resolve_type(
  301. self._element_type_name, self.info,
  302. self.info and self.info.defn_meta)
  303. assert not isinstance(self.element_type, QAPISchemaArrayType)
  304. def set_module(self, schema):
  305. self._set_module(schema, self.element_type.info)
  306. @property
  307. def ifcond(self):
  308. assert self._checked
  309. return self.element_type.ifcond
  310. def is_implicit(self):
  311. return True
  312. def c_type(self):
  313. return c_name(self.name) + POINTER_SUFFIX
  314. def json_type(self):
  315. return 'array'
  316. def doc_type(self):
  317. elt_doc_type = self.element_type.doc_type()
  318. if not elt_doc_type:
  319. return None
  320. return 'array of ' + elt_doc_type
  321. def visit(self, visitor):
  322. super().visit(visitor)
  323. visitor.visit_array_type(self.name, self.info, self.ifcond,
  324. self.element_type)
  325. def describe(self):
  326. assert self.meta
  327. return "%s type ['%s']" % (self.meta, self._element_type_name)
  328. class QAPISchemaObjectType(QAPISchemaType):
  329. def __init__(self, name, info, doc, ifcond, features,
  330. base, local_members, variants):
  331. # struct has local_members, optional base, and no variants
  332. # union has base, variants, and no local_members
  333. super().__init__(name, info, doc, ifcond, features)
  334. self.meta = 'union' if variants else 'struct'
  335. assert base is None or isinstance(base, str)
  336. for m in local_members:
  337. assert isinstance(m, QAPISchemaObjectTypeMember)
  338. m.set_defined_in(name)
  339. if variants is not None:
  340. assert isinstance(variants, QAPISchemaVariants)
  341. variants.set_defined_in(name)
  342. self._base_name = base
  343. self.base = None
  344. self.local_members = local_members
  345. self.variants = variants
  346. self.members = None
  347. def check(self, schema):
  348. # This calls another type T's .check() exactly when the C
  349. # struct emitted by gen_object() contains that T's C struct
  350. # (pointers don't count).
  351. if self.members is not None:
  352. # A previous .check() completed: nothing to do
  353. return
  354. if self._checked:
  355. # Recursed: C struct contains itself
  356. raise QAPISemError(self.info,
  357. "object %s contains itself" % self.name)
  358. super().check(schema)
  359. assert self._checked and self.members is None
  360. seen = OrderedDict()
  361. if self._base_name:
  362. self.base = schema.resolve_type(self._base_name, self.info,
  363. "'base'")
  364. if (not isinstance(self.base, QAPISchemaObjectType)
  365. or self.base.variants):
  366. raise QAPISemError(
  367. self.info,
  368. "'base' requires a struct type, %s isn't"
  369. % self.base.describe())
  370. self.base.check(schema)
  371. self.base.check_clash(self.info, seen)
  372. for m in self.local_members:
  373. m.check(schema)
  374. m.check_clash(self.info, seen)
  375. members = seen.values()
  376. if self.variants:
  377. self.variants.check(schema, seen)
  378. self.variants.check_clash(self.info, seen)
  379. self.members = members # mark completed
  380. # Check that the members of this type do not cause duplicate JSON members,
  381. # and update seen to track the members seen so far. Report any errors
  382. # on behalf of info, which is not necessarily self.info
  383. def check_clash(self, info, seen):
  384. assert self._checked
  385. for m in self.members:
  386. m.check_clash(info, seen)
  387. if self.variants:
  388. self.variants.check_clash(info, seen)
  389. def connect_doc(self, doc=None):
  390. super().connect_doc(doc)
  391. doc = doc or self.doc
  392. if self.base and self.base.is_implicit():
  393. self.base.connect_doc(doc)
  394. for m in self.local_members:
  395. m.connect_doc(doc)
  396. def is_implicit(self):
  397. # See QAPISchema._make_implicit_object_type(), as well as
  398. # _def_predefineds()
  399. return self.name.startswith('q_')
  400. def is_empty(self):
  401. assert self.members is not None
  402. return not self.members and not self.variants
  403. def has_conditional_members(self):
  404. assert self.members is not None
  405. return any(m.ifcond.is_present() for m in self.members)
  406. def c_name(self):
  407. assert self.name != 'q_empty'
  408. return super().c_name()
  409. def c_type(self):
  410. assert not self.is_implicit()
  411. return c_name(self.name) + POINTER_SUFFIX
  412. def c_unboxed_type(self):
  413. return c_name(self.name)
  414. def json_type(self):
  415. return 'object'
  416. def visit(self, visitor):
  417. super().visit(visitor)
  418. visitor.visit_object_type(
  419. self.name, self.info, self.ifcond, self.features,
  420. self.base, self.local_members, self.variants)
  421. visitor.visit_object_type_flat(
  422. self.name, self.info, self.ifcond, self.features,
  423. self.members, self.variants)
  424. class QAPISchemaAlternateType(QAPISchemaType):
  425. meta = 'alternate'
  426. def __init__(self, name, info, doc, ifcond, features, variants):
  427. super().__init__(name, info, doc, ifcond, features)
  428. assert isinstance(variants, QAPISchemaVariants)
  429. assert variants.tag_member
  430. variants.set_defined_in(name)
  431. variants.tag_member.set_defined_in(self.name)
  432. self.variants = variants
  433. def check(self, schema):
  434. super().check(schema)
  435. self.variants.tag_member.check(schema)
  436. # Not calling self.variants.check_clash(), because there's nothing
  437. # to clash with
  438. self.variants.check(schema, {})
  439. # Alternate branch names have no relation to the tag enum values;
  440. # so we have to check for potential name collisions ourselves.
  441. seen = {}
  442. types_seen = {}
  443. for v in self.variants.variants:
  444. v.check_clash(self.info, seen)
  445. qtype = v.type.alternate_qtype()
  446. if not qtype:
  447. raise QAPISemError(
  448. self.info,
  449. "%s cannot use %s"
  450. % (v.describe(self.info), v.type.describe()))
  451. conflicting = set([qtype])
  452. if qtype == 'QTYPE_QSTRING':
  453. if isinstance(v.type, QAPISchemaEnumType):
  454. for m in v.type.members:
  455. if m.name in ['on', 'off']:
  456. conflicting.add('QTYPE_QBOOL')
  457. if re.match(r'[-+0-9.]', m.name):
  458. # lazy, could be tightened
  459. conflicting.add('QTYPE_QNUM')
  460. else:
  461. conflicting.add('QTYPE_QNUM')
  462. conflicting.add('QTYPE_QBOOL')
  463. for qt in conflicting:
  464. if qt in types_seen:
  465. raise QAPISemError(
  466. self.info,
  467. "%s can't be distinguished from '%s'"
  468. % (v.describe(self.info), types_seen[qt]))
  469. types_seen[qt] = v.name
  470. def connect_doc(self, doc=None):
  471. super().connect_doc(doc)
  472. doc = doc or self.doc
  473. for v in self.variants.variants:
  474. v.connect_doc(doc)
  475. def c_type(self):
  476. return c_name(self.name) + POINTER_SUFFIX
  477. def json_type(self):
  478. return 'value'
  479. def visit(self, visitor):
  480. super().visit(visitor)
  481. visitor.visit_alternate_type(
  482. self.name, self.info, self.ifcond, self.features, self.variants)
  483. class QAPISchemaVariants:
  484. def __init__(self, tag_name, info, tag_member, variants):
  485. # Unions pass tag_name but not tag_member.
  486. # Alternates pass tag_member but not tag_name.
  487. # After check(), tag_member is always set.
  488. assert bool(tag_member) != bool(tag_name)
  489. assert (isinstance(tag_name, str) or
  490. isinstance(tag_member, QAPISchemaObjectTypeMember))
  491. for v in variants:
  492. assert isinstance(v, QAPISchemaVariant)
  493. self._tag_name = tag_name
  494. self.info = info
  495. self.tag_member = tag_member
  496. self.variants = variants
  497. def set_defined_in(self, name):
  498. for v in self.variants:
  499. v.set_defined_in(name)
  500. def check(self, schema, seen):
  501. if self._tag_name: # union
  502. self.tag_member = seen.get(c_name(self._tag_name))
  503. base = "'base'"
  504. # Pointing to the base type when not implicit would be
  505. # nice, but we don't know it here
  506. if not self.tag_member or self._tag_name != self.tag_member.name:
  507. raise QAPISemError(
  508. self.info,
  509. "discriminator '%s' is not a member of %s"
  510. % (self._tag_name, base))
  511. # Here we do:
  512. base_type = schema.lookup_type(self.tag_member.defined_in)
  513. assert base_type
  514. if not base_type.is_implicit():
  515. base = "base type '%s'" % self.tag_member.defined_in
  516. if not isinstance(self.tag_member.type, QAPISchemaEnumType):
  517. raise QAPISemError(
  518. self.info,
  519. "discriminator member '%s' of %s must be of enum type"
  520. % (self._tag_name, base))
  521. if self.tag_member.optional:
  522. raise QAPISemError(
  523. self.info,
  524. "discriminator member '%s' of %s must not be optional"
  525. % (self._tag_name, base))
  526. if self.tag_member.ifcond.is_present():
  527. raise QAPISemError(
  528. self.info,
  529. "discriminator member '%s' of %s must not be conditional"
  530. % (self._tag_name, base))
  531. else: # alternate
  532. assert isinstance(self.tag_member.type, QAPISchemaEnumType)
  533. assert not self.tag_member.optional
  534. assert not self.tag_member.ifcond.is_present()
  535. if self._tag_name: # union
  536. # branches that are not explicitly covered get an empty type
  537. cases = {v.name for v in self.variants}
  538. for m in self.tag_member.type.members:
  539. if m.name not in cases:
  540. v = QAPISchemaVariant(m.name, self.info,
  541. 'q_empty', m.ifcond)
  542. v.set_defined_in(self.tag_member.defined_in)
  543. self.variants.append(v)
  544. if not self.variants:
  545. raise QAPISemError(self.info, "union has no branches")
  546. for v in self.variants:
  547. v.check(schema)
  548. # Union names must match enum values; alternate names are
  549. # checked separately. Use 'seen' to tell the two apart.
  550. if seen:
  551. if v.name not in self.tag_member.type.member_names():
  552. raise QAPISemError(
  553. self.info,
  554. "branch '%s' is not a value of %s"
  555. % (v.name, self.tag_member.type.describe()))
  556. if not isinstance(v.type, QAPISchemaObjectType):
  557. raise QAPISemError(
  558. self.info,
  559. "%s cannot use %s"
  560. % (v.describe(self.info), v.type.describe()))
  561. v.type.check(schema)
  562. def check_clash(self, info, seen):
  563. for v in self.variants:
  564. # Reset seen map for each variant, since qapi names from one
  565. # branch do not affect another branch
  566. v.type.check_clash(info, dict(seen))
  567. class QAPISchemaMember:
  568. """ Represents object members, enum members and features """
  569. role = 'member'
  570. def __init__(self, name, info, ifcond=None):
  571. assert isinstance(name, str)
  572. self.name = name
  573. self.info = info
  574. self.ifcond = ifcond or QAPISchemaIfCond()
  575. self.defined_in = None
  576. def set_defined_in(self, name):
  577. assert not self.defined_in
  578. self.defined_in = name
  579. def check_clash(self, info, seen):
  580. cname = c_name(self.name)
  581. if cname in seen:
  582. raise QAPISemError(
  583. info,
  584. "%s collides with %s"
  585. % (self.describe(info), seen[cname].describe(info)))
  586. seen[cname] = self
  587. def connect_doc(self, doc):
  588. if doc:
  589. doc.connect_member(self)
  590. def describe(self, info):
  591. role = self.role
  592. meta = 'type'
  593. defined_in = self.defined_in
  594. assert defined_in
  595. if defined_in.startswith('q_obj_'):
  596. # See QAPISchema._make_implicit_object_type() - reverse the
  597. # mapping there to create a nice human-readable description
  598. defined_in = defined_in[6:]
  599. if defined_in.endswith('-arg'):
  600. # Implicit type created for a command's dict 'data'
  601. assert role == 'member'
  602. role = 'parameter'
  603. meta = 'command'
  604. defined_in = defined_in[:-4]
  605. elif defined_in.endswith('-base'):
  606. # Implicit type created for a union's dict 'base'
  607. role = 'base ' + role
  608. defined_in = defined_in[:-5]
  609. else:
  610. assert False
  611. if defined_in != info.defn_name:
  612. return "%s '%s' of %s '%s'" % (role, self.name, meta, defined_in)
  613. return "%s '%s'" % (role, self.name)
  614. class QAPISchemaEnumMember(QAPISchemaMember):
  615. role = 'value'
  616. def __init__(self, name, info, ifcond=None, features=None):
  617. super().__init__(name, info, ifcond)
  618. for f in features or []:
  619. assert isinstance(f, QAPISchemaFeature)
  620. f.set_defined_in(name)
  621. self.features = features or []
  622. def connect_doc(self, doc):
  623. super().connect_doc(doc)
  624. if doc:
  625. for f in self.features:
  626. doc.connect_feature(f)
  627. class QAPISchemaFeature(QAPISchemaMember):
  628. role = 'feature'
  629. def is_special(self):
  630. return self.name in ('deprecated', 'unstable')
  631. class QAPISchemaObjectTypeMember(QAPISchemaMember):
  632. def __init__(self, name, info, typ, optional, ifcond=None, features=None):
  633. super().__init__(name, info, ifcond)
  634. assert isinstance(typ, str)
  635. assert isinstance(optional, bool)
  636. for f in features or []:
  637. assert isinstance(f, QAPISchemaFeature)
  638. f.set_defined_in(name)
  639. self._type_name = typ
  640. self.type = None
  641. self.optional = optional
  642. self.features = features or []
  643. def need_has(self):
  644. assert self.type
  645. return self.optional and self.type.need_has_if_optional()
  646. def check(self, schema):
  647. assert self.defined_in
  648. self.type = schema.resolve_type(self._type_name, self.info,
  649. self.describe)
  650. seen = {}
  651. for f in self.features:
  652. f.check_clash(self.info, seen)
  653. def connect_doc(self, doc):
  654. super().connect_doc(doc)
  655. if doc:
  656. for f in self.features:
  657. doc.connect_feature(f)
  658. class QAPISchemaVariant(QAPISchemaObjectTypeMember):
  659. role = 'branch'
  660. def __init__(self, name, info, typ, ifcond=None):
  661. super().__init__(name, info, typ, False, ifcond)
  662. class QAPISchemaCommand(QAPISchemaDefinition):
  663. meta = 'command'
  664. def __init__(self, name, info, doc, ifcond, features,
  665. arg_type, ret_type,
  666. gen, success_response, boxed, allow_oob, allow_preconfig,
  667. coroutine):
  668. super().__init__(name, info, doc, ifcond, features)
  669. assert not arg_type or isinstance(arg_type, str)
  670. assert not ret_type or isinstance(ret_type, str)
  671. self._arg_type_name = arg_type
  672. self.arg_type = None
  673. self._ret_type_name = ret_type
  674. self.ret_type = None
  675. self.gen = gen
  676. self.success_response = success_response
  677. self.boxed = boxed
  678. self.allow_oob = allow_oob
  679. self.allow_preconfig = allow_preconfig
  680. self.coroutine = coroutine
  681. def check(self, schema):
  682. super().check(schema)
  683. if self._arg_type_name:
  684. self.arg_type = schema.resolve_type(
  685. self._arg_type_name, self.info, "command's 'data'")
  686. if not isinstance(self.arg_type, QAPISchemaObjectType):
  687. raise QAPISemError(
  688. self.info,
  689. "command's 'data' cannot take %s"
  690. % self.arg_type.describe())
  691. if self.arg_type.variants and not self.boxed:
  692. raise QAPISemError(
  693. self.info,
  694. "command's 'data' can take %s only with 'boxed': true"
  695. % self.arg_type.describe())
  696. self.arg_type.check(schema)
  697. if self.arg_type.has_conditional_members() and not self.boxed:
  698. raise QAPISemError(
  699. self.info,
  700. "conditional command arguments require 'boxed': true")
  701. if self._ret_type_name:
  702. self.ret_type = schema.resolve_type(
  703. self._ret_type_name, self.info, "command's 'returns'")
  704. if self.name not in self.info.pragma.command_returns_exceptions:
  705. typ = self.ret_type
  706. if isinstance(typ, QAPISchemaArrayType):
  707. typ = self.ret_type.element_type
  708. assert typ
  709. if not isinstance(typ, QAPISchemaObjectType):
  710. raise QAPISemError(
  711. self.info,
  712. "command's 'returns' cannot take %s"
  713. % self.ret_type.describe())
  714. def connect_doc(self, doc=None):
  715. super().connect_doc(doc)
  716. doc = doc or self.doc
  717. if doc:
  718. if self.arg_type and self.arg_type.is_implicit():
  719. self.arg_type.connect_doc(doc)
  720. def visit(self, visitor):
  721. super().visit(visitor)
  722. visitor.visit_command(
  723. self.name, self.info, self.ifcond, self.features,
  724. self.arg_type, self.ret_type, self.gen, self.success_response,
  725. self.boxed, self.allow_oob, self.allow_preconfig,
  726. self.coroutine)
  727. class QAPISchemaEvent(QAPISchemaDefinition):
  728. meta = 'event'
  729. def __init__(self, name, info, doc, ifcond, features, arg_type, boxed):
  730. super().__init__(name, info, doc, ifcond, features)
  731. assert not arg_type or isinstance(arg_type, str)
  732. self._arg_type_name = arg_type
  733. self.arg_type = None
  734. self.boxed = boxed
  735. def check(self, schema):
  736. super().check(schema)
  737. if self._arg_type_name:
  738. self.arg_type = schema.resolve_type(
  739. self._arg_type_name, self.info, "event's 'data'")
  740. if not isinstance(self.arg_type, QAPISchemaObjectType):
  741. raise QAPISemError(
  742. self.info,
  743. "event's 'data' cannot take %s"
  744. % self.arg_type.describe())
  745. if self.arg_type.variants and not self.boxed:
  746. raise QAPISemError(
  747. self.info,
  748. "event's 'data' can take %s only with 'boxed': true"
  749. % self.arg_type.describe())
  750. self.arg_type.check(schema)
  751. if self.arg_type.has_conditional_members() and not self.boxed:
  752. raise QAPISemError(
  753. self.info,
  754. "conditional event arguments require 'boxed': true")
  755. def connect_doc(self, doc=None):
  756. super().connect_doc(doc)
  757. doc = doc or self.doc
  758. if doc:
  759. if self.arg_type and self.arg_type.is_implicit():
  760. self.arg_type.connect_doc(doc)
  761. def visit(self, visitor):
  762. super().visit(visitor)
  763. visitor.visit_event(
  764. self.name, self.info, self.ifcond, self.features,
  765. self.arg_type, self.boxed)
  766. class QAPISchema:
  767. def __init__(self, fname):
  768. self.fname = fname
  769. try:
  770. parser = QAPISchemaParser(fname)
  771. except OSError as err:
  772. raise QAPIError(
  773. f"can't read schema file '{fname}': {err.strerror}"
  774. ) from err
  775. exprs = check_exprs(parser.exprs)
  776. self.docs = parser.docs
  777. self._entity_list = []
  778. self._entity_dict = {}
  779. self._module_dict = OrderedDict()
  780. self._schema_dir = os.path.dirname(fname)
  781. self._make_module(QAPISchemaModule.BUILTIN_MODULE_NAME)
  782. self._make_module(fname)
  783. self._predefining = True
  784. self._def_predefineds()
  785. self._predefining = False
  786. self._def_exprs(exprs)
  787. self.check()
  788. def _def_entity(self, ent):
  789. self._entity_list.append(ent)
  790. def _def_definition(self, defn):
  791. # Only the predefined types are allowed to not have info
  792. assert defn.info or self._predefining
  793. self._def_entity(defn)
  794. # TODO reject names that differ only in '_' vs. '.' vs. '-',
  795. # because they're liable to clash in generated C.
  796. other_defn = self._entity_dict.get(defn.name)
  797. if other_defn:
  798. if other_defn.info:
  799. where = QAPISourceError(other_defn.info, "previous definition")
  800. raise QAPISemError(
  801. defn.info,
  802. "'%s' is already defined\n%s" % (defn.name, where))
  803. raise QAPISemError(
  804. defn.info, "%s is already defined" % other_defn.describe())
  805. self._entity_dict[defn.name] = defn
  806. def lookup_entity(self, name, typ=None):
  807. ent = self._entity_dict.get(name)
  808. if typ and not isinstance(ent, typ):
  809. return None
  810. return ent
  811. def lookup_type(self, name):
  812. return self.lookup_entity(name, QAPISchemaType)
  813. def resolve_type(self, name, info, what):
  814. typ = self.lookup_type(name)
  815. if not typ:
  816. if callable(what):
  817. what = what(info)
  818. raise QAPISemError(
  819. info, "%s uses unknown type '%s'" % (what, name))
  820. return typ
  821. def _module_name(self, fname: str) -> str:
  822. if QAPISchemaModule.is_system_module(fname):
  823. return fname
  824. return os.path.relpath(fname, self._schema_dir)
  825. def _make_module(self, fname):
  826. name = self._module_name(fname)
  827. if name not in self._module_dict:
  828. self._module_dict[name] = QAPISchemaModule(name)
  829. return self._module_dict[name]
  830. def module_by_fname(self, fname):
  831. name = self._module_name(fname)
  832. return self._module_dict[name]
  833. def _def_include(self, expr: QAPIExpression):
  834. include = expr['include']
  835. assert expr.doc is None
  836. self._def_entity(
  837. QAPISchemaInclude(self._make_module(include), expr.info))
  838. def _def_builtin_type(self, name, json_type, c_type):
  839. self._def_definition(QAPISchemaBuiltinType(name, json_type, c_type))
  840. # Instantiating only the arrays that are actually used would
  841. # be nice, but we can't as long as their generated code
  842. # (qapi-builtin-types.[ch]) may be shared by some other
  843. # schema.
  844. self._make_array_type(name, None)
  845. def _def_predefineds(self):
  846. for t in [('str', 'string', 'char' + POINTER_SUFFIX),
  847. ('number', 'number', 'double'),
  848. ('int', 'int', 'int64_t'),
  849. ('int8', 'int', 'int8_t'),
  850. ('int16', 'int', 'int16_t'),
  851. ('int32', 'int', 'int32_t'),
  852. ('int64', 'int', 'int64_t'),
  853. ('uint8', 'int', 'uint8_t'),
  854. ('uint16', 'int', 'uint16_t'),
  855. ('uint32', 'int', 'uint32_t'),
  856. ('uint64', 'int', 'uint64_t'),
  857. ('size', 'int', 'uint64_t'),
  858. ('bool', 'boolean', 'bool'),
  859. ('any', 'value', 'QObject' + POINTER_SUFFIX),
  860. ('null', 'null', 'QNull' + POINTER_SUFFIX)]:
  861. self._def_builtin_type(*t)
  862. self.the_empty_object_type = QAPISchemaObjectType(
  863. 'q_empty', None, None, None, None, None, [], None)
  864. self._def_definition(self.the_empty_object_type)
  865. qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
  866. 'qbool']
  867. qtype_values = self._make_enum_members(
  868. [{'name': n} for n in qtypes], None)
  869. self._def_definition(QAPISchemaEnumType(
  870. 'QType', None, None, None, None, qtype_values, 'QTYPE'))
  871. def _make_features(self, features, info):
  872. if features is None:
  873. return []
  874. return [QAPISchemaFeature(f['name'], info,
  875. QAPISchemaIfCond(f.get('if')))
  876. for f in features]
  877. def _make_enum_member(self, name, ifcond, features, info):
  878. return QAPISchemaEnumMember(name, info,
  879. QAPISchemaIfCond(ifcond),
  880. self._make_features(features, info))
  881. def _make_enum_members(self, values, info):
  882. return [self._make_enum_member(v['name'], v.get('if'),
  883. v.get('features'), info)
  884. for v in values]
  885. def _make_array_type(self, element_type, info):
  886. name = element_type + 'List' # reserved by check_defn_name_str()
  887. if not self.lookup_type(name):
  888. self._def_definition(QAPISchemaArrayType(
  889. name, info, element_type))
  890. return name
  891. def _make_implicit_object_type(self, name, info, ifcond, role, members):
  892. if not members:
  893. return None
  894. # See also QAPISchemaObjectTypeMember.describe()
  895. name = 'q_obj_%s-%s' % (name, role)
  896. typ = self.lookup_entity(name, QAPISchemaObjectType)
  897. if typ:
  898. # The implicit object type has multiple users. This can
  899. # only be a duplicate definition, which will be flagged
  900. # later.
  901. pass
  902. else:
  903. self._def_definition(QAPISchemaObjectType(
  904. name, info, None, ifcond, None, None, members, None))
  905. return name
  906. def _def_enum_type(self, expr: QAPIExpression):
  907. name = expr['enum']
  908. data = expr['data']
  909. prefix = expr.get('prefix')
  910. ifcond = QAPISchemaIfCond(expr.get('if'))
  911. info = expr.info
  912. features = self._make_features(expr.get('features'), info)
  913. self._def_definition(QAPISchemaEnumType(
  914. name, info, expr.doc, ifcond, features,
  915. self._make_enum_members(data, info), prefix))
  916. def _make_member(self, name, typ, ifcond, features, info):
  917. optional = False
  918. if name.startswith('*'):
  919. name = name[1:]
  920. optional = True
  921. if isinstance(typ, list):
  922. assert len(typ) == 1
  923. typ = self._make_array_type(typ[0], info)
  924. return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond,
  925. self._make_features(features, info))
  926. def _make_members(self, data, info):
  927. return [self._make_member(key, value['type'],
  928. QAPISchemaIfCond(value.get('if')),
  929. value.get('features'), info)
  930. for (key, value) in data.items()]
  931. def _def_struct_type(self, expr: QAPIExpression):
  932. name = expr['struct']
  933. base = expr.get('base')
  934. data = expr['data']
  935. info = expr.info
  936. ifcond = QAPISchemaIfCond(expr.get('if'))
  937. features = self._make_features(expr.get('features'), info)
  938. self._def_definition(QAPISchemaObjectType(
  939. name, info, expr.doc, ifcond, features, base,
  940. self._make_members(data, info),
  941. None))
  942. def _make_variant(self, case, typ, ifcond, info):
  943. if isinstance(typ, list):
  944. assert len(typ) == 1
  945. typ = self._make_array_type(typ[0], info)
  946. return QAPISchemaVariant(case, info, typ, ifcond)
  947. def _def_union_type(self, expr: QAPIExpression):
  948. name = expr['union']
  949. base = expr['base']
  950. tag_name = expr['discriminator']
  951. data = expr['data']
  952. assert isinstance(data, dict)
  953. info = expr.info
  954. ifcond = QAPISchemaIfCond(expr.get('if'))
  955. features = self._make_features(expr.get('features'), info)
  956. if isinstance(base, dict):
  957. base = self._make_implicit_object_type(
  958. name, info, ifcond,
  959. 'base', self._make_members(base, info))
  960. variants = [
  961. self._make_variant(key, value['type'],
  962. QAPISchemaIfCond(value.get('if')),
  963. info)
  964. for (key, value) in data.items()]
  965. members: List[QAPISchemaObjectTypeMember] = []
  966. self._def_definition(
  967. QAPISchemaObjectType(name, info, expr.doc, ifcond, features,
  968. base, members,
  969. QAPISchemaVariants(
  970. tag_name, info, None, variants)))
  971. def _def_alternate_type(self, expr: QAPIExpression):
  972. name = expr['alternate']
  973. data = expr['data']
  974. assert isinstance(data, dict)
  975. ifcond = QAPISchemaIfCond(expr.get('if'))
  976. info = expr.info
  977. features = self._make_features(expr.get('features'), info)
  978. variants = [
  979. self._make_variant(key, value['type'],
  980. QAPISchemaIfCond(value.get('if')),
  981. info)
  982. for (key, value) in data.items()]
  983. tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
  984. self._def_definition(
  985. QAPISchemaAlternateType(
  986. name, info, expr.doc, ifcond, features,
  987. QAPISchemaVariants(None, info, tag_member, variants)))
  988. def _def_command(self, expr: QAPIExpression):
  989. name = expr['command']
  990. data = expr.get('data')
  991. rets = expr.get('returns')
  992. gen = expr.get('gen', True)
  993. success_response = expr.get('success-response', True)
  994. boxed = expr.get('boxed', False)
  995. allow_oob = expr.get('allow-oob', False)
  996. allow_preconfig = expr.get('allow-preconfig', False)
  997. coroutine = expr.get('coroutine', False)
  998. ifcond = QAPISchemaIfCond(expr.get('if'))
  999. info = expr.info
  1000. features = self._make_features(expr.get('features'), info)
  1001. if isinstance(data, OrderedDict):
  1002. data = self._make_implicit_object_type(
  1003. name, info, ifcond,
  1004. 'arg', self._make_members(data, info))
  1005. if isinstance(rets, list):
  1006. assert len(rets) == 1
  1007. rets = self._make_array_type(rets[0], info)
  1008. self._def_definition(
  1009. QAPISchemaCommand(name, info, expr.doc, ifcond, features, data,
  1010. rets, gen, success_response, boxed, allow_oob,
  1011. allow_preconfig, coroutine))
  1012. def _def_event(self, expr: QAPIExpression):
  1013. name = expr['event']
  1014. data = expr.get('data')
  1015. boxed = expr.get('boxed', False)
  1016. ifcond = QAPISchemaIfCond(expr.get('if'))
  1017. info = expr.info
  1018. features = self._make_features(expr.get('features'), info)
  1019. if isinstance(data, OrderedDict):
  1020. data = self._make_implicit_object_type(
  1021. name, info, ifcond,
  1022. 'arg', self._make_members(data, info))
  1023. self._def_definition(QAPISchemaEvent(name, info, expr.doc, ifcond,
  1024. features, data, boxed))
  1025. def _def_exprs(self, exprs):
  1026. for expr in exprs:
  1027. if 'enum' in expr:
  1028. self._def_enum_type(expr)
  1029. elif 'struct' in expr:
  1030. self._def_struct_type(expr)
  1031. elif 'union' in expr:
  1032. self._def_union_type(expr)
  1033. elif 'alternate' in expr:
  1034. self._def_alternate_type(expr)
  1035. elif 'command' in expr:
  1036. self._def_command(expr)
  1037. elif 'event' in expr:
  1038. self._def_event(expr)
  1039. elif 'include' in expr:
  1040. self._def_include(expr)
  1041. else:
  1042. assert False
  1043. def check(self):
  1044. for ent in self._entity_list:
  1045. ent.check(self)
  1046. ent.connect_doc()
  1047. for ent in self._entity_list:
  1048. ent.set_module(self)
  1049. for doc in self.docs:
  1050. doc.check()
  1051. def visit(self, visitor):
  1052. visitor.visit_begin(self)
  1053. for mod in self._module_dict.values():
  1054. mod.visit(visitor)
  1055. visitor.visit_end()