Message ID | 20180211093607.27351-18-armbru@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 02/11/2018 03:35 AM, Markus Armbruster wrote: > 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> > --- > @@ -1479,16 +1497,19 @@ class QAPISchema(object): > self._entity_dict = {} > self._predefining = True > self._def_predefineds() > - self._predefining = False > self._def_exprs(exprs) > self.check() Why does self._predfining not need to be toggled anymore? Do we even need this variable any more... > > 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 ...and/or is this assert now worthless? > +++ b/tests/qapi-schema/comments.out > @@ -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'] Based on the generated output, it looks like you can tell whether you are in the predefining stage by not having any module at all; the first visit_module call is what flips the switch that everything else is defined by a module and must therefore have associated info.
Eric Blake <eblake@redhat.com> writes: > On 02/11/2018 03:35 AM, Markus Armbruster wrote: >> 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> >> --- >> @@ -1479,16 +1497,19 @@ class QAPISchema(object): >> self._entity_dict = {} >> self._predefining = True >> self._def_predefineds() >> - self._predefining = False >> self._def_exprs(exprs) >> self.check() > > Why does self._predfining not need to be toggled anymore? Do we even > need this variable any more... > >> >> 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 > > ...and/or is this assert now worthless? > > >> +++ b/tests/qapi-schema/comments.out >> @@ -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'] > > Based on the generated output, it looks like you can tell whether you > are in the predefining stage by not having any module at all; the > first visit_module call is what flips the switch that everything else > is defined by a module and must therefore have associated info. Editing accident. I started down the road you described, decided I lack the time to reach its end, then failed to back out completely.
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py index b531ab519f..29d98ca934 100644 --- a/scripts/qapi/common.py +++ b/scripts/qapi/common.py @@ -985,8 +985,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 @@ -1015,10 +1016,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 @@ -1045,6 +1052,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. @@ -1472,6 +1489,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 @@ -1479,16 +1497,19 @@ class QAPISchema(object): self._entity_dict = {} self._predefining = True self._def_predefineds() - self._predefining = False self._def_exprs(exprs) self.check() 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) @@ -1499,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 @@ -1681,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 @@ -1691,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() diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out index 0261ddf202..8d2f1ce8a2 100644 --- a/tests/qapi-schema/comments.out +++ b/tests/qapi-schema/comments.out @@ -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'] diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/qapi-schema/doc-bad-section.out index 23bf8c71ab..cd28721568 100644 --- a/tests/qapi-schema/doc-bad-section.out +++ b/tests/qapi-schema/doc-bad-section.out @@ -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= diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 0c07301f07..430b5a87db 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -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 diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out index 110571b793..88c0964917 100644 --- a/tests/qapi-schema/event-case.out +++ b/tests/qapi-schema/event-case.out @@ -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 diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out index 8336aa7629..ee3b34e623 100644 --- a/tests/qapi-schema/ident-with-escape.out +++ b/tests/qapi-schema/ident-with-escape.out @@ -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 diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out index 0261ddf202..ebbabd7a18 100644 --- a/tests/qapi-schema/include-relpath.out +++ b/tests/qapi-schema/include-relpath.out @@ -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'] diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out index 0261ddf202..7235e055bc 100644 --- a/tests/qapi-schema/include-repetition.out +++ b/tests/qapi-schema/include-repetition.out @@ -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 diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out index 0261ddf202..006f723eeb 100644 --- a/tests/qapi-schema/include-simple.out +++ b/tests/qapi-schema/include-simple.out @@ -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'] diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out index 34de8be426..a79935e8c3 100644 --- a/tests/qapi-schema/indented-expr.out +++ b/tests/qapi-schema/indented-expr.out @@ -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 diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 50706b0136..012e7fc06a 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -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 diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index 4da14b43af..67e417e298 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -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: