All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: qemu-devel@nongnu.org, Michael Roth <mdroth@linux.vnet.ibm.com>,
	armbru@redhat.com, "Dr. David Alan Gilbert" <dgilbert@redhat.com>,
	Gerd Hoffmann <kraxel@redhat.com>,
	Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v6 07/15] qapi: add #if/#endif helpers
Date: Tue, 03 Jul 2018 13:53:15 +0200	[thread overview]
Message-ID: <87sh50bkno.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <20180627163551.31610-8-marcandre.lureau@redhat.com> ("Marc-André Lureau"'s message of "Wed, 27 Jun 2018 18:35:43 +0200")

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

> Add helpers to wrap generated code with #if/#endif lines.
>
> Add QAPIGenCSnippet class to write C snippet code, make QAPIGenC
> inherit from it, for full C files with copyright headers etc.

It's called QAPIGenCCode now.  Can touch up when I apply, along with
another instance below.

Leaves the reader wondering *why* you need to splice QAPIGenCCode
between QAPIGen and QAPIGenC.  Becomes clear only in PATCH 10.
Providing the class now reduces code churn, but you should explain why.
Perhaps:

  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>
> ---
>  scripts/qapi/common.py | 101 +++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 97 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
> index 1b56065a80..44eaf25850 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):

Looks like a helper method.  Name it _wrap_ifcond?

> +    if ifcond is None or before == after:
> +        return after

The before == after part suppresses empty conditionals.  Suggest

           return after            # suppress empty #if ... #endif

The ifcond is None part is suppresses "non-conditionals".  How can this
happen?  If it can't, let's drop this part.

Another non-conditional is [].  See below.

> +
> +    assert after.startswith(before)
> +    out = before
> +    added = after[len(before):]
> +    if added[0] == '\n':
> +        out += '\n'
> +        added = added[1:]

The conditional adjusts vertical space around #if.  This might need
tweaking, but let's not worry about that now.

> +    out += gen_if(ifcond)
> +    out += added
> +    out += gen_endif(ifcond)

There's no similar adjustment for #endif.  Again, let's not worry about
that now.

> +    return out
> +
> +

Since gen_if([]) and gen_endif([]) return '', wrap_ifcond([], before,
after) returns after.  Okay.

>  def gen_enum_lookup(name, values, prefix=None):
>      ret = mcgen('''
>  
> @@ -2064,6 +2099,7 @@ class QAPIGen(object):
>      def __init__(self):
>          self._preamble = ''
>          self._body = ''
> +        self._start_if = None
>  
>      def preamble_add(self, text):
>          self._preamble += text
> @@ -2071,6 +2107,25 @@ class QAPIGen(object):
>      def add(self, text):
>          self._body += text
>  
> +    def start_if(self, ifcond):
> +        assert self._start_if is None
> +

Let's drop this blank line.

> +        self._start_if = (ifcond, self._body, self._preamble)

It's now obvious that you can't nest .start_if() ... .endif().  Good.

> +
> +    def _wrap_ifcond(self):
> +        pass
> +
> +    def end_if(self):
> +        assert self._start_if
> +

Let's drop this blank line.

> +        self._wrap_ifcond()
> +        self._start_if = None
> +
> +    def get_content(self, fname=None):
> +        assert self._start_if is None
> +        return (self._top(fname) + self._preamble + self._body
> +                + self._bottom(fname))
> +
>      def _top(self, fname):
>          return ''
>  

Note for later: all this code has no effect unless ._wrap_ifcond() is
overridden.

> @@ -2091,8 +2146,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 +2155,49 @@ 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: variable length argument list of QAPIGen

Perhaps: any number of QAPIGen objects

> +
> +    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()
> +

Can we drop this blank line?

> +    """
> +    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)
> +
> +    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)

Can you explain why you put the machinery for conditionals in QAPIGen
and not QAPIGenCCode?

> +
> +
> +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))

  reply	other threads:[~2018-07-03 11:53 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-27 16:35 [Qemu-devel] [PATCH v6 00/15] qapi: add #if pre-processor conditions to generated code (part 1) Marc-André Lureau
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 01/15] qapi: add 'if' to top-level expressions Marc-André Lureau
2018-06-28 14:57   ` Markus Armbruster
2018-06-28 15:34     ` Marc-André Lureau
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 02/15] tests Marc-André Lureau
2018-06-27 16:39   ` Marc-André Lureau
2018-06-28 15:35     ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 03/15] qapi: pass 'if' condition into QAPISchemaEntity objects Marc-André Lureau
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 04/15] qapi: leave the ifcond attribute undefined until check() Marc-André Lureau
2018-06-28 17:45   ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 05/15] qapi: add 'ifcond' to visitor methods Marc-André Lureau
2018-06-28 17:48   ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 06/15] qapi: mcgen() shouldn't indent # lines Marc-André Lureau
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 07/15] qapi: add #if/#endif helpers Marc-André Lureau
2018-07-03 11:53   ` Markus Armbruster [this message]
2018-07-03 12:35     ` Marc-André Lureau
2018-07-03 13:37       ` Markus Armbruster
2018-07-03 15:08         ` Marc-André Lureau
2018-07-03 15:34           ` Markus Armbruster
2018-07-03 15:43             ` Marc-André Lureau
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 08/15] qapi-introspect: modify to_qlit() to append ', ' on level > 0 Marc-André Lureau
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 09/15] qapi-introspect: add preprocessor conditions to generated QLit Marc-André Lureau
2018-07-03 12:09   ` Markus Armbruster
2018-07-03 13:11     ` Marc-André Lureau
2018-07-03 13:47       ` Markus Armbruster
2018-07-03 15:08         ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 10/15] qapi/commands: add #if conditions to commands Marc-André Lureau
2018-07-03 14:43   ` Markus Armbruster
2018-07-03 15:09     ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 11/15] qapi/events: add #if conditions to events Marc-André Lureau
2018-07-03 14:47   ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 12/15] qapi-types: add #if conditions to types & visitors Marc-André Lureau
2018-07-03 14:50   ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 13/15] qapi: add 'If:' section to generated documentation Marc-André Lureau
2018-07-03 14:59   ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 14/15] qapi: add conditions to VNC type/commands/events on the schema Marc-André Lureau
2018-07-03 15:04   ` Markus Armbruster
2018-06-27 16:35 ` [Qemu-devel] [PATCH v6 15/15] qapi: add conditions to SPICE " Marc-André Lureau
2018-07-03 15:05   ` Markus Armbruster

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=87sh50bkno.fsf@dusky.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=kraxel@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=pbonzini@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.