qapi: Record 'include' directives in intermediate representation
The include directive permits modular QAPI schemata, but the generated code is monolithic all the same. To permit generating modular code, the front end needs to pass more information on inclusions to the back ends. The commit before last added the necessary information to the parse tree. This commit adds it to the intermediate representation and its QAPISchemaVisitor. A later commit will use this to to generate modular code. New entity QAPISchemaInclude represents inclusions. Call new visitor method visit_include() for it, so visitors can see the sub-modules a module includes. Note that unlike other entities, QAPISchemaInclude has no name, and is therefore not added to entity_dict. New QAPISchemaEntity attribute @module names the entity's source file. Call new visitor method visit_module() when it changes during a visit, so visitors can keep track of the module being visited. Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20180211093607.27351-18-armbru@redhat.com> [eblake: avoid accidental deletion of self._predefining] Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
8a84767cc4
commit
cf40a0a5c2
@ -984,8 +984,9 @@ def check_exprs(exprs):
|
||||
|
||||
class QAPISchemaEntity(object):
|
||||
def __init__(self, name, info, doc):
|
||||
assert isinstance(name, str)
|
||||
assert name is None or isinstance(name, str)
|
||||
self.name = name
|
||||
self.module = None
|
||||
# For explicitly defined entities, info points to the (explicit)
|
||||
# definition. For builtins (and their arrays), info is None.
|
||||
# For implicitly defined entities, info points to a place that
|
||||
@ -1014,10 +1015,16 @@ class QAPISchemaVisitor(object):
|
||||
def visit_end(self):
|
||||
pass
|
||||
|
||||
def visit_module(self, fname):
|
||||
pass
|
||||
|
||||
def visit_needed(self, entity):
|
||||
# Default to visiting everything
|
||||
return True
|
||||
|
||||
def visit_include(self, fname, info):
|
||||
pass
|
||||
|
||||
def visit_builtin_type(self, name, info, json_type):
|
||||
pass
|
||||
|
||||
@ -1044,6 +1051,16 @@ class QAPISchemaVisitor(object):
|
||||
pass
|
||||
|
||||
|
||||
class QAPISchemaInclude(QAPISchemaEntity):
|
||||
|
||||
def __init__(self, fname, info):
|
||||
QAPISchemaEntity.__init__(self, None, info, None)
|
||||
self.fname = fname
|
||||
|
||||
def visit(self, visitor):
|
||||
visitor.visit_include(self.fname, self.info)
|
||||
|
||||
|
||||
class QAPISchemaType(QAPISchemaEntity):
|
||||
# Return the C type for common use.
|
||||
# For the types we commonly box, this is a pointer type.
|
||||
@ -1471,6 +1488,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
|
||||
|
||||
class QAPISchema(object):
|
||||
def __init__(self, fname):
|
||||
self._fname = fname
|
||||
parser = QAPISchemaParser(open(fname, 'r'))
|
||||
exprs = check_exprs(parser.exprs)
|
||||
self.docs = parser.docs
|
||||
@ -1485,9 +1503,13 @@ class QAPISchema(object):
|
||||
def _def_entity(self, ent):
|
||||
# Only the predefined types are allowed to not have info
|
||||
assert ent.info or self._predefining
|
||||
assert ent.name not in self._entity_dict
|
||||
assert ent.name is None or ent.name not in self._entity_dict
|
||||
self._entity_list.append(ent)
|
||||
self._entity_dict[ent.name] = ent
|
||||
if ent.name is not None:
|
||||
self._entity_dict[ent.name] = ent
|
||||
if ent.info:
|
||||
ent.module = os.path.relpath(ent.info['file'],
|
||||
os.path.dirname(self._fname))
|
||||
|
||||
def lookup_entity(self, name, typ=None):
|
||||
ent = self._entity_dict.get(name)
|
||||
@ -1498,6 +1520,15 @@ class QAPISchema(object):
|
||||
def lookup_type(self, name):
|
||||
return self.lookup_entity(name, QAPISchemaType)
|
||||
|
||||
def _def_include(self, expr, info, doc):
|
||||
include = expr['include']
|
||||
assert doc is None
|
||||
main_info = info
|
||||
while main_info['parent']:
|
||||
main_info = main_info['parent']
|
||||
fname = os.path.relpath(include, os.path.dirname(main_info['file']))
|
||||
self._def_entity(QAPISchemaInclude(fname, info))
|
||||
|
||||
def _def_builtin_type(self, name, json_type, c_type):
|
||||
self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
|
||||
# TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
|
||||
@ -1680,7 +1711,7 @@ class QAPISchema(object):
|
||||
elif 'event' in expr:
|
||||
self._def_event(expr, info, doc)
|
||||
elif 'include' in expr:
|
||||
pass
|
||||
self._def_include(expr, info, doc)
|
||||
else:
|
||||
assert False
|
||||
|
||||
@ -1690,8 +1721,12 @@ class QAPISchema(object):
|
||||
|
||||
def visit(self, visitor):
|
||||
visitor.visit_begin(self)
|
||||
module = None
|
||||
for entity in self._entity_list:
|
||||
if visitor.visit_needed(entity):
|
||||
if entity.module != module:
|
||||
module = entity.module
|
||||
visitor.visit_module(module)
|
||||
entity.visit(visitor)
|
||||
visitor.visit_end()
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module comments.json
|
||||
enum Status ['good', 'bad', 'ugly']
|
||||
|
@ -1,6 +1,7 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module doc-bad-section.json
|
||||
enum Enum ['one', 'two']
|
||||
doc symbol=Enum
|
||||
body=
|
||||
|
@ -1,6 +1,7 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module doc-good.json
|
||||
enum Enum ['one', 'two']
|
||||
object Base
|
||||
member base1: Enum optional=False
|
||||
|
@ -1,5 +1,6 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module event-case.json
|
||||
event oops None
|
||||
boxed=False
|
||||
|
@ -1,6 +1,7 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module ident-with-escape.json
|
||||
object q_obj_fooA-arg
|
||||
member bar1: str optional=False
|
||||
command fooA q_obj_fooA-arg -> None
|
||||
|
@ -1,4 +1,9 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module include-relpath.json
|
||||
include include/relpath.json
|
||||
module include/relpath.json
|
||||
include include-relpath-sub.json
|
||||
module include-relpath-sub.json
|
||||
enum Status ['good', 'bad', 'ugly']
|
||||
|
@ -1,4 +1,14 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module include-repetition.json
|
||||
include comments.json
|
||||
module comments.json
|
||||
enum Status ['good', 'bad', 'ugly']
|
||||
module include-repetition.json
|
||||
include include-repetition-sub.json
|
||||
module include-repetition-sub.json
|
||||
include comments.json
|
||||
include comments.json
|
||||
module include-repetition.json
|
||||
include comments.json
|
||||
|
@ -1,4 +1,7 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module include-simple.json
|
||||
include include-simple-sub.json
|
||||
module include-simple-sub.json
|
||||
enum Status ['good', 'bad', 'ugly']
|
||||
|
@ -1,6 +1,7 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module indented-expr.json
|
||||
command eins None -> None
|
||||
gen=True success_response=True boxed=False
|
||||
command zwei None -> None
|
||||
|
@ -1,6 +1,7 @@
|
||||
object q_empty
|
||||
enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool']
|
||||
prefix QTYPE
|
||||
module qapi-schema-test.json
|
||||
object TestStruct
|
||||
member integer: int optional=False
|
||||
member boolean: bool optional=False
|
||||
|
@ -16,6 +16,13 @@ from qapi.common import QAPIError, QAPISchema, QAPISchemaVisitor
|
||||
|
||||
|
||||
class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
||||
|
||||
def visit_module(self, name):
|
||||
print('module %s' % name)
|
||||
|
||||
def visit_include(self, name, info):
|
||||
print('include %s' % name)
|
||||
|
||||
def visit_enum_type(self, name, info, values, prefix):
|
||||
print('enum %s %s' % (name, values))
|
||||
if prefix:
|
||||
|
Loading…
Reference in New Issue
Block a user