schema.py 41 KB

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