qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Subject: [Qemu-devel] [PULL 06/14] qapi: add #if/#endif helpers
Date: Tue,  3 Jul 2018 23:06:05 +0200	[thread overview]
Message-ID: <20180703210613.25619-7-armbru@redhat.com> (raw)
In-Reply-To: <20180703210613.25619-1-armbru@redhat.com>

From: Marc-André Lureau <marcandre.lureau@redhat.com>

Add helpers to wrap generated code with #if/#endif lines.

A later patch wants to use QAPIGen for generating C snippets rather
than full C files with copyright headers etc.  Splice in class
QAPIGenCCode between QAPIGen and QAPIGenC.

Add a 'with' statement context manager that will be used to wrap
generator visitor methods.  The manager will check if code was
generated before adding #if/#endif lines on QAPIGenCSnippet
objects. Used in the following patches.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20180703155648.11933-7-marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi/common.py | 98 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 94 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 1b56065a80..9230a2a3e8 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -12,6 +12,7 @@
 # See the COPYING file in the top-level directory.
 
 from __future__ import print_function
+from contextlib import contextmanager
 import errno
 import os
 import re
@@ -1974,6 +1975,40 @@ def guardend(name):
                  name=guardname(name))
 
 
+def gen_if(ifcond):
+    ret = ''
+    for ifc in ifcond:
+        ret += mcgen('''
+#if %(cond)s
+''', cond=ifc)
+    return ret
+
+
+def gen_endif(ifcond):
+    ret = ''
+    for ifc in reversed(ifcond):
+        ret += mcgen('''
+#endif /* %(cond)s */
+''', cond=ifc)
+    return ret
+
+
+def _wrap_ifcond(ifcond, before, after):
+    if before == after:
+        return after   # suppress empty #if ... #endif
+
+    assert after.startswith(before)
+    out = before
+    added = after[len(before):]
+    if added[0] == '\n':
+        out += '\n'
+        added = added[1:]
+    out += gen_if(ifcond)
+    out += added
+    out += gen_endif(ifcond)
+    return out
+
+
 def gen_enum_lookup(name, values, prefix=None):
     ret = mcgen('''
 
@@ -2071,6 +2106,10 @@ class QAPIGen(object):
     def add(self, text):
         self._body += text
 
+    def get_content(self, fname=None):
+        return (self._top(fname) + self._preamble + self._body
+                + self._bottom(fname))
+
     def _top(self, fname):
         return ''
 
@@ -2091,8 +2130,7 @@ class QAPIGen(object):
             f = open(fd, 'r+', encoding='utf-8')
         else:
             f = os.fdopen(fd, 'r+')
-        text = (self._top(fname) + self._preamble + self._body
-                + self._bottom(fname))
+        text = self.get_content(fname)
         oldtext = f.read(len(text) + 1)
         if text != oldtext:
             f.seek(0)
@@ -2101,10 +2139,62 @@ class QAPIGen(object):
         f.close()
 
 
-class QAPIGenC(QAPIGen):
+@contextmanager
+def ifcontext(ifcond, *args):
+    """A 'with' statement context manager to wrap with start_if()/end_if()
 
-    def __init__(self, blurb, pydoc):
+    *args: any number of QAPIGenCCode
+
+    Example::
+
+        with ifcontext(ifcond, self._genh, self._genc):
+            modify self._genh and self._genc ...
+
+    Is equivalent to calling::
+
+        self._genh.start_if(ifcond)
+        self._genc.start_if(ifcond)
+        modify self._genh and self._genc ...
+        self._genh.end_if()
+        self._genc.end_if()
+    """
+    for arg in args:
+        arg.start_if(ifcond)
+    yield
+    for arg in args:
+        arg.end_if()
+
+
+class QAPIGenCCode(QAPIGen):
+
+    def __init__(self):
         QAPIGen.__init__(self)
+        self._start_if = None
+
+    def start_if(self, ifcond):
+        assert self._start_if is None
+        self._start_if = (ifcond, self._body, self._preamble)
+
+    def end_if(self):
+        assert self._start_if
+        self._wrap_ifcond()
+        self._start_if = None
+
+    def _wrap_ifcond(self):
+        self._body = _wrap_ifcond(self._start_if[0],
+                                  self._start_if[1], self._body)
+        self._preamble = _wrap_ifcond(self._start_if[0],
+                                      self._start_if[2], self._preamble)
+
+    def get_content(self, fname=None):
+        assert self._start_if is None
+        return QAPIGen.get_content(self, fname)
+
+
+class QAPIGenC(QAPIGenCCode):
+
+    def __init__(self, blurb, pydoc):
+        QAPIGenCCode.__init__(self)
         self._blurb = blurb
         self._copyright = '\n * '.join(re.findall(r'^Copyright .*', pydoc,
                                                   re.MULTILINE))
-- 
2.17.1

  parent reply	other threads:[~2018-07-03 21:06 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-03 21:05 [Qemu-devel] [PULL 00/14] QAPI patches for 2018-07-03 Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 01/14] qapi: add 'if' to top-level expressions Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 02/14] qapi: pass 'if' condition into QAPISchemaEntity objects Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 03/14] qapi: leave the ifcond attribute undefined until check() Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 04/14] qapi: add 'ifcond' to visitor methods Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 05/14] qapi: mcgen() shouldn't indent # lines Markus Armbruster
2018-07-03 21:06 ` Markus Armbruster [this message]
2018-07-03 21:06 ` [Qemu-devel] [PULL 07/14] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 08/14] qapi-introspect: add preprocessor conditions to generated QLit Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 09/14] qapi/commands: add #if conditions to commands Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 10/14] qapi/events: add #if conditions to events Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 11/14] qapi-types: add #if conditions to types & visitors Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 12/14] qapi: add 'If:' section to generated documentation Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 13/14] qapi: add conditions to VNC type/commands/events on the schema Markus Armbruster
2018-07-03 21:06 ` [Qemu-devel] [PULL 14/14] qapi: add conditions to SPICE " Markus Armbruster
2018-07-05 10:25 ` [Qemu-devel] [PULL 00/14] QAPI patches for 2018-07-03 Peter Maydell

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=20180703210613.25619-7-armbru@redhat.com \
    --to=armbru@redhat.com \
    --cc=marcandre.lureau@redhat.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).