All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Marc-André Lureau" <marcandre.lureau@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: Eric Blake <eblake@redhat.com>, John Snow <jsnow@redhat.com>,
	qemu-devel <qemu-devel@nongnu.org>,
	Stefan Hajnoczi <stefanha@redhat.com>
Subject: Re: [PATCH v6 05/11] qapi: introduce QAPISchemaIfCond.cgen()
Date: Wed, 4 Aug 2021 12:23:01 +0400	[thread overview]
Message-ID: <CAMxuvawMFPLxFcndyJ9YdFBJFr-9c0deFN3BvnOyceEae21quQ@mail.gmail.com> (raw)
In-Reply-To: <87pmuvoqek.fsf@dusky.pond.sub.org>

[-- Attachment #1: Type: text/plain, Size: 13065 bytes --]

Hi

On Mon, Aug 2, 2021 at 6:46 PM Markus Armbruster <armbru@redhat.com> wrote:

> marcandre.lureau@redhat.com writes:
>
> > From: Marc-André Lureau <marcandre.lureau@redhat.com>
> >
> > Instead of building prepocessor conditions from a list of string, use
> > the result generated from QAPISchemaIfCond.cgen() and hide the
> > implementation details.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> Please mention that the patch changes generated code.  See below for
> details.
>

I'll add

    Note: this patch introduces a minor regression, generating a redundant
    pair of parenthesis. This is fixed in a later patch in this
    series ("qapi: replace if condition list with dict [..]")


> > ---
> >  scripts/qapi/common.py     | 35 ++++++++++++++++++++++-------------
> >  scripts/qapi/gen.py        |  4 ++--
> >  scripts/qapi/introspect.py |  4 ++--
> >  scripts/qapi/schema.py     |  5 ++++-
> >  scripts/qapi/types.py      | 20 ++++++++++----------
> >  scripts/qapi/visit.py      | 12 ++++++------
> >  6 files changed, 46 insertions(+), 34 deletions(-)
> >
> > diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
> > index 6ad1eeb61d..ba9fe14e4b 100644
> > --- a/scripts/qapi/common.py
> > +++ b/scripts/qapi/common.py
> > @@ -12,7 +12,12 @@
> >  # See the COPYING file in the top-level directory.
> >
> >  import re
> > -from typing import Match, Optional, Sequence
> > +from typing import (
> > +    List,
> > +    Match,
> > +    Optional,
> > +    Union,
> > +)
> >
> >
> >  #: Magic string that gets removed along with all space to its right.
> > @@ -194,22 +199,26 @@ def guardend(name: str) -> str:
> >                   name=c_fname(name).upper())
> >
> >
> > -def gen_if(ifcond: Sequence[str]) -> str:
> > -    ret = ''
> > -    for ifc in ifcond:
> > -        ret += mcgen('''
> > +def cgen_ifcond(ifcond: Union[str, List[str]]) -> str:
> > +    if not ifcond:
> > +        return ''
> > +    return '(' + ') && ('.join(ifcond) + ')'
> > +
> > +
> > +def gen_if(cond: str) -> str:
> > +    if not cond:
> > +        return ''
> > +    return mcgen('''
> >  #if %(cond)s
> > -''', cond=ifc)
> > -    return ret
> > +''', cond=cond)
> >
> >
> > -def gen_endif(ifcond: Sequence[str]) -> str:
> > -    ret = ''
> > -    for ifc in reversed(ifcond):
> > -        ret += mcgen('''
> > +def gen_endif(cond: str) -> str:
> > +    if not cond:
> > +        return ''
> > +    return mcgen('''
> >  #endif /* %(cond)s */
> > -''', cond=ifc)
> > -    return ret
> > +''', cond=cond)
> >
> >
>
> This patch does three things:
>
> (1) Change gen_if(), gen_endif() to always generate a single #if,
>     #endif.  This enables:
>
> (2) Factor cgen_ifcond() out of gen_if() and gen_endif()
>
> (3) Lift the call of cgen_ifcond() into into gen_if()'s, gen_endif()'s
>     callers.
>
> I'd split the patch.  This is *not* a demand.
>
> The motivation for (3) is unclear.  Is it so gen_if() doesn't depend on
> QAPISchemaIfCond?
>
> Step (1) affects the generated code.  When @ifcond is [COND1, COND2, ...],
> gen_if()'s value changes from
>
>     #if COND1
>     #if COND2
>     ...
>
> to
>
>     #if (COND1) && (COND2)
>
> Example: in tests/test-qapi-introspect.c
>
>     @@ -259,11 +257,9 @@ const QLitObject test_qmp_schema_qlit =
>          QLIT_QDICT(((QLitDictEntry[]) {
>              { "arg-type", QLIT_QSTR("1"), },
>              { "features", QLIT_QLIST(((QLitObject[]) {
>     -#if defined(TEST_IF_COND_1)
>     -#if defined(TEST_IF_COND_2)
>     +#if (defined(TEST_IF_COND_1)) && (defined(TEST_IF_COND_2))
>                  QLIT_QSTR("feature1"),
>     -#endif /* defined(TEST_IF_COND_2) */
>     -#endif /* defined(TEST_IF_COND_1) */
>     +#endif /* (defined(TEST_IF_COND_1)) && (defined(TEST_IF_COND_2)) */
>                  {}
>              })), },
>              { "meta-type", QLIT_QSTR("command"), },
>
> The common case: when it's just [COND], the value changes from
>
>     #if COND
>
> to
>
>     #if (COND)
>
> which is a bit ugly.
>
> Example: in qapi-types-block-export.c
>
>     @@ -76,7 +76,7 @@ const QEnumLookup FuseExportAllowOther_l
>          .size = FUSE_EXPORT_ALLOW_OTHER__MAX
>      };
>
>     -#if defined(CONFIG_FUSE)
>     +#if (defined(CONFIG_FUSE))
>      void qapi_free_BlockExportOptionsFuse(BlockExportOptionsFuse *obj)
>      {
>          Visitor *v;
>     @@ -89,7 +89,7 @@ void qapi_free_BlockExportOptionsFuse(Bl
>          visit_type_BlockExportOptionsFuse(v, NULL, &obj, NULL);
>          visit_free(v);
>      }
>     -#endif /* defined(CONFIG_FUSE) */
>     +#endif /* (defined(CONFIG_FUSE)) */
>
>      void qapi_free_NbdServerAddOptions(NbdServerAddOptions *obj)
>      {
>
> Avoiding the redundant pair of parenthesis takes another special case.
> Let's do it.
>
> >  def must_match(pattern: str, string: str) -> Match[str]:
> > diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
> > index 1c5b190276..51a597a025 100644
> > --- a/scripts/qapi/gen.py
> > +++ b/scripts/qapi/gen.py
> > @@ -95,9 +95,9 @@ def _wrap_ifcond(ifcond: QAPISchemaIfCond, before:
> str, after: str) -> str:
> >      if added[0] == '\n':
> >          out += '\n'
> >          added = added[1:]
> > -    out += gen_if(ifcond.ifcond)
> > +    out += gen_if(ifcond.cgen())
> >      out += added
> > -    out += gen_endif(ifcond.ifcond)
> > +    out += gen_endif(ifcond.cgen())
> >      return out
> >
> >
>
> > diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
> > index 77a8c33ad4..474b08fd4d 100644
> > --- a/scripts/qapi/introspect.py
> > +++ b/scripts/qapi/introspect.py
> > @@ -124,10 +124,10 @@ def indent(level: int) -> str:
> >          if obj.comment:
> >              ret += indent(level) + f"/* {obj.comment} */\n"
> >          if obj.ifcond:
> > -            ret += gen_if(obj.ifcond.ifcond)
> > +            ret += gen_if(obj.ifcond.cgen())
> >          ret += _tree_to_qlit(obj.value, level)
> >          if obj.ifcond:
> > -            ret += '\n' + gen_endif(obj.ifcond.ifcond)
> > +            ret += '\n' + gen_endif(obj.ifcond.cgen())
> >          return ret
> >
> >      ret = ''
> > diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
> > index c35fa3bf51..70120f0dcc 100644
> > --- a/scripts/qapi/schema.py
> > +++ b/scripts/qapi/schema.py
> > @@ -19,7 +19,7 @@
> >  import re
> >  from typing import Optional
> >
> > -from .common import POINTER_SUFFIX, c_name
> > +from .common import POINTER_SUFFIX, c_name, cgen_ifcond
> >  from .error import QAPIError, QAPISemError, QAPISourceError
> >  from .expr import check_exprs
> >  from .parser import QAPISchemaParser
> > @@ -29,6 +29,9 @@ class QAPISchemaIfCond:
> >      def __init__(self, ifcond=None):
> >          self.ifcond = ifcond or []
> >
> > +    def cgen(self):
> > +        return cgen_ifcond(self.ifcond)
> > +
>
> As far as I can tell, this is only ever used like
>
>        gen_if(obj.ifcond.cgen())
>
> and
>
>        gen_endif(obj.ifcond.cgen())
>
> Wouldn't
>
>        obj.ifcond.gen_if()
>
> and
>
>        obj.ifcond.gen_endif()
>
> be neater?
>

Yes


> Not a demand, since we can get there on top if we want to.
>
> >      def is_present(self):
> >          return bool(self.ifcond)
> >
> > diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
> > index 3673cf0f49..db9ff95bd1 100644
> > --- a/scripts/qapi/types.py
> > +++ b/scripts/qapi/types.py
> > @@ -51,13 +51,13 @@ def gen_enum_lookup(name: str,
> >  ''',
> >                  c_name=c_name(name))
> >      for memb in members:
> > -        ret += gen_if(memb.ifcond.ifcond)
> > +        ret += gen_if(memb.ifcond.cgen())
> >          index = c_enum_const(name, memb.name, prefix)
> >          ret += mcgen('''
> >          [%(index)s] = "%(name)s",
> >  ''',
> >                       index=index, name=memb.name)
> > -        ret += gen_endif(memb.ifcond.ifcond)
> > +        ret += gen_endif(memb.ifcond.cgen())
> >
> >      ret += mcgen('''
> >      },
> > @@ -81,12 +81,12 @@ def gen_enum(name: str,
> >                  c_name=c_name(name))
> >
> >      for memb in enum_members:
> > -        ret += gen_if(memb.ifcond.ifcond)
> > +        ret += gen_if(memb.ifcond.cgen())
> >          ret += mcgen('''
> >      %(c_enum)s,
> >  ''',
> >                       c_enum=c_enum_const(name, memb.name, prefix))
> > -        ret += gen_endif(memb.ifcond.ifcond)
> > +        ret += gen_endif(memb.ifcond.cgen())
> >
> >      ret += mcgen('''
> >  } %(c_name)s;
> > @@ -126,7 +126,7 @@ def gen_array(name: str, element_type:
> QAPISchemaType) -> str:
> >  def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) ->
> str:
> >      ret = ''
> >      for memb in members:
> > -        ret += gen_if(memb.ifcond.ifcond)
> > +        ret += gen_if(memb.ifcond.cgen())
> >          if memb.optional:
> >              ret += mcgen('''
> >      bool has_%(c_name)s;
> > @@ -136,7 +136,7 @@ def gen_struct_members(members:
> List[QAPISchemaObjectTypeMember]) -> str:
> >      %(c_type)s %(c_name)s;
> >  ''',
> >                       c_type=memb.type.c_type(), c_name=c_name(memb.name
> ))
> > -        ret += gen_endif(memb.ifcond.ifcond)
> > +        ret += gen_endif(memb.ifcond.cgen())
> >      return ret
> >
> >
> > @@ -159,7 +159,7 @@ def gen_object(name: str, ifcond: QAPISchemaIfCond,
> >      ret += mcgen('''
> >
> >  ''')
> > -    ret += gen_if(ifcond.ifcond)
> > +    ret += gen_if(ifcond.cgen())
> >      ret += mcgen('''
> >  struct %(c_name)s {
> >  ''',
> > @@ -193,7 +193,7 @@ def gen_object(name: str, ifcond: QAPISchemaIfCond,
> >      ret += mcgen('''
> >  };
> >  ''')
> > -    ret += gen_endif(ifcond.ifcond)
> > +    ret += gen_endif(ifcond.cgen())
> >
> >      return ret
> >
> > @@ -220,13 +220,13 @@ def gen_variants(variants: QAPISchemaVariants) ->
> str:
> >      for var in variants.variants:
> >          if var.type.name == 'q_empty':
> >              continue
> > -        ret += gen_if(var.ifcond.ifcond)
> > +        ret += gen_if(var.ifcond.cgen())
> >          ret += mcgen('''
> >          %(c_type)s %(c_name)s;
> >  ''',
> >                       c_type=var.type.c_unboxed_type(),
> >                       c_name=c_name(var.name))
> > -        ret += gen_endif(var.ifcond.ifcond)
> > +        ret += gen_endif(var.ifcond.cgen())
> >
> >      ret += mcgen('''
> >      } u;
> > diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
> > index 67721b2470..56ea516399 100644
> > --- a/scripts/qapi/visit.py
> > +++ b/scripts/qapi/visit.py
> > @@ -79,7 +79,7 @@ def gen_visit_object_members(name: str,
> >
> >      for memb in members:
> >          deprecated = 'deprecated' in [f.name for f in memb.features]
> > -        ret += gen_if(memb.ifcond.ifcond)
> > +        ret += gen_if(memb.ifcond.cgen())
> >          if memb.optional:
> >              ret += mcgen('''
> >      if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
> > @@ -112,7 +112,7 @@ def gen_visit_object_members(name: str,
> >              ret += mcgen('''
> >      }
> >  ''')
> > -        ret += gen_endif(memb.ifcond.ifcond)
> > +        ret += gen_endif(memb.ifcond.cgen())
> >
> >      if variants:
> >          tag_member = variants.tag_member
> > @@ -126,7 +126,7 @@ def gen_visit_object_members(name: str,
> >          for var in variants.variants:
> >              case_str = c_enum_const(tag_member.type.name, var.name,
> >                                      tag_member.type.prefix)
> > -            ret += gen_if(var.ifcond.ifcond)
> > +            ret += gen_if(var.ifcond.cgen())
> >              if var.type.name == 'q_empty':
> >                  # valid variant and nothing to do
> >                  ret += mcgen('''
> > @@ -142,7 +142,7 @@ def gen_visit_object_members(name: str,
> >                               case=case_str,
> >                               c_type=var.type.c_name(), c_name=c_name(
> var.name))
> >
> > -            ret += gen_endif(var.ifcond.ifcond)
> > +            ret += gen_endif(var.ifcond.cgen())
> >          ret += mcgen('''
> >      default:
> >          abort();
> > @@ -228,7 +228,7 @@ def gen_visit_alternate(name: str, variants:
> QAPISchemaVariants) -> str:
> >                  c_name=c_name(name))
> >
> >      for var in variants.variants:
> > -        ret += gen_if(var.ifcond.ifcond)
> > +        ret += gen_if(var.ifcond.cgen())
> >          ret += mcgen('''
> >      case %(case)s:
> >  ''',
> > @@ -254,7 +254,7 @@ def gen_visit_alternate(name: str, variants:
> QAPISchemaVariants) -> str:
> >          ret += mcgen('''
> >          break;
> >  ''')
> > -        ret += gen_endif(var.ifcond.ifcond)
> > +        ret += gen_endif(var.ifcond.cgen())
> >
> >      ret += mcgen('''
> >      case QTYPE_NONE:
>
>

[-- Attachment #2: Type: text/html, Size: 18001 bytes --]

  parent reply	other threads:[~2021-08-04  8:25 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-18 10:24 [PATCH v6 00/11] qapi: untie 'if' conditions from C preprocessor marcandre.lureau
2021-06-18 10:24 ` [PATCH v6 01/11] docs: update the documentation upfront about schema configuration marcandre.lureau
2021-07-12 14:07   ` Markus Armbruster
2021-06-18 10:24 ` [PATCH v6 02/11] qapi: wrap Sequence[str] in an object marcandre.lureau
2021-08-02  9:21   ` Markus Armbruster
2021-08-03 17:55     ` John Snow
2021-08-04  8:22     ` Marc-André Lureau
2021-08-05 10:44       ` Markus Armbruster
2021-08-06 11:19       ` Markus Armbruster
2021-06-18 10:24 ` [PATCH v6 03/11] qapi: add QAPISchemaIfCond.is_present() marcandre.lureau
2021-08-02  9:52   ` Markus Armbruster
2021-08-04  8:22     ` Marc-André Lureau
2021-06-18 10:25 ` [PATCH v6 04/11] qapi: _make_enum_members() to work with pre-built QAPISchemaIfCond marcandre.lureau
2021-08-02 10:41   ` Markus Armbruster
2021-08-04  8:22     ` Marc-André Lureau
2021-06-18 10:25 ` [PATCH v6 05/11] qapi: introduce QAPISchemaIfCond.cgen() marcandre.lureau
2021-08-02 14:46   ` Markus Armbruster
2021-08-03 11:19     ` Markus Armbruster
2021-08-03 11:20       ` Markus Armbruster
2021-08-03 11:23         ` Markus Armbruster
2021-08-04  8:23     ` Marc-André Lureau [this message]
2021-06-18 10:25 ` [PATCH v6 06/11] qapidoc: introduce QAPISchemaIfCond.docgen() marcandre.lureau
2021-08-02 15:47   ` Markus Armbruster
2021-08-04  8:23     ` Marc-André Lureau
2021-06-18 10:25 ` [PATCH v6 07/11] qapi: replace if condition list with dict {'all': [...]} marcandre.lureau
2021-08-03 13:05   ` Markus Armbruster
2021-08-04  8:23     ` Marc-André Lureau
2021-08-05 15:11     ` John Snow
2021-08-03 13:17   ` Markus Armbruster
2021-06-18 10:25 ` [PATCH v6 08/11] qapi: add 'any' condition marcandre.lureau
2021-08-03 13:20   ` Markus Armbruster
2021-06-18 10:25 ` [PATCH v6 09/11] qapi: convert 'if' C-expressions to the new syntax tree marcandre.lureau
2021-08-03 13:22   ` Markus Armbruster
2021-06-18 10:25 ` [PATCH v6 10/11] qapi: add 'not' condition operation marcandre.lureau
2021-06-18 10:25 ` [PATCH v6 11/11] qapi: make 'if' condition strings simple identifiers marcandre.lureau
2021-08-03 13:35   ` Markus Armbruster
2021-08-04  8:22     ` Marc-André Lureau
2021-08-03 13:44 ` [PATCH v6 00/11] qapi: untie 'if' conditions from C preprocessor Markus Armbruster
2021-08-04  8:25   ` Marc-André Lureau

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=CAMxuvawMFPLxFcndyJ9YdFBJFr-9c0deFN3BvnOyceEae21quQ@mail.gmail.com \
    --to=marcandre.lureau@redhat.com \
    --cc=armbru@redhat.com \
    --cc=eblake@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /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.