qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: qemu-devel@nongnu.org
Cc: Markus Armbruster <armbru@redhat.com>,
	Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: [Qemu-devel] [PULL 17/30] qapi: Record 'include' directives in intermediate representation
Date: Thu,  1 Mar 2018 13:42:32 -0600	[thread overview]
Message-ID: <20180301194245.29854-18-eblake@redhat.com> (raw)
In-Reply-To: <20180301194245.29854-1-eblake@redhat.com>

From: Markus Armbruster <armbru@redhat.com>

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>
---
 scripts/qapi/common.py                   | 43 +++++++++++++++++++++++++++++---
 tests/qapi-schema/comments.out           |  1 +
 tests/qapi-schema/doc-bad-section.out    |  1 +
 tests/qapi-schema/doc-good.out           |  1 +
 tests/qapi-schema/event-case.out         |  1 +
 tests/qapi-schema/ident-with-escape.out  |  1 +
 tests/qapi-schema/include-relpath.out    |  5 ++++
 tests/qapi-schema/include-repetition.out | 10 ++++++++
 tests/qapi-schema/include-simple.out     |  3 +++
 tests/qapi-schema/indented-expr.out      |  1 +
 tests/qapi-schema/qapi-schema-test.out   |  1 +
 tests/qapi-schema/test-qapi.py           |  7 ++++++
 12 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 1aa1cd3b9bd..2c5c40ec0a9 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -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()

diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index 0261ddf202c..8d2f1ce8a2e 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 23bf8c71aba..cd287215689 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 0c07301f07a..430b5a87db3 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 110571b793c..88c0964917a 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 8336aa7629d..ee3b34e623e 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 0261ddf202c..ebbabd7a186 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 0261ddf202c..7235e055bc1 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 0261ddf202c..006f723eebc 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 34de8be4262..a79935e8c32 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 50706b01369..012e7fc06a5 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 4da14b43af6..67e417e2980 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:
-- 
2.14.3

  parent reply	other threads:[~2018-03-01 19:43 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-01 19:42 [Qemu-devel] [PULL 00/30] QAPI patches for 2018-03-01 Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 01/30] Include qapi/qmp/qerror.h exactly where needed Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 02/30] qapi: Streamline boilerplate comment generation Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 03/30] qapi: Generate up-to-date copyright notice Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 04/30] qapi: Rename variable holding the QAPISchemaGenFOOVisitor Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 05/30] qapi: New classes QAPIGenC, QAPIGenH, QAPIGenDoc Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 06/30] qapi: Reduce use of global variables in generators some Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 07/30] qapi: Turn generators into modules Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 08/30] qapi-gen: New common driver for code and doc generators Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 09/30] qapi-gen: Convert from getopt to argparse Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 10/30] qapi: Touch generated files only when they change Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 11/30] qapi: Improve include file name reporting in error messages Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 12/30] qapi/common: Eliminate QAPISchema.exprs Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 13/30] qapi: Lift error reporting from QAPISchema.__init__() to callers Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 14/30] qapi: Concentrate QAPISchemaParser.exprs updates in .__init__() Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 15/30] qapi: Record 'include' directives in parse tree Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 16/30] qapi: Generate in source order Eric Blake
2018-03-01 19:42 ` Eric Blake [this message]
2018-03-01 19:42 ` [Qemu-devel] [PULL 18/30] qapi: Rename generated qmp-marshal.c to qmp-commands.c Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 19/30] qapi: Make code-generating visitors use QAPIGen more Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 20/30] qapi/types qapi/visit: Generate built-in stuff into separate files Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 21/30] qapi/common: Fix guardname() for funny filenames Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 22/30] qapi: Generate separate .h, .c for each module Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 23/30] Include less of the generated modular QAPI headers Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 24/30] watchdog: Consolidate QAPI into single file Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 25/30] qapi: Empty out qapi-schema.json Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 26/30] docs/devel/writing-qmp-commands: Update for modular QAPI Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 27/30] docs: Correct outdated information on QAPI Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 28/30] qapi: Move qapi-schema.json to qapi/, rename generated files Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 29/30] Fix up dangling references to qmp-commands.* in comment and doc Eric Blake
2018-03-01 19:42 ` [Qemu-devel] [PULL 30/30] qapi: Don't create useless directory qapi-generated Eric Blake
2018-03-01 20:54 ` [Qemu-devel] [PULL 00/30] QAPI patches for 2018-03-01 no-reply
2018-03-01 21:00   ` Eric Blake
2018-03-01 21:03 ` no-reply
2018-03-01 21:31 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180301194245.29854-18-eblake@redhat.com \
    --to=eblake@redhat.com \
    --cc=armbru@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).