qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v6 15/16] qapi: Share gen_err_check()


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH v6 15/16] qapi: Share gen_err_check()
Date: Tue, 29 Sep 2015 16:31:23 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Eric Blake <address@hidden> writes:

> qapi-commands had a nice helper gen_err_check(), but did not

In fact, it still has :)

> use it everywhere. In fact, using it in more places makes it
> easier to reduce the lines of code used in appending an error

Suggest "used for generating error checks"

> check in generated code (previously required a multi-line
> mcgen(), which didn't add any use of parameterization), which
> in turn makes it easier to write the next patch which will
> consolidate another common pattern among the generators.

I think we should burn some of the whiches ;)

Drop the paranthesis?

> The diffstat of this patch doesn't quite show as big a
> reduction in lines as I had hoped, but that is in part due to

Almost none...

> the duplication of some FIXME comments.
>
> Signed-off-by: Eric Blake <address@hidden>

Have you diffed the generated code before and after the patch?

> ---
> v6: new, split off of 10/46, add label parameter, and catch more
> instances that could use it
> ---
>  scripts/qapi-commands.py | 29 +++++++-------------
>  scripts/qapi-event.py    | 16 +++++------
>  scripts/qapi-visit.py    | 69 
> ++++++++++++++++++++++++------------------------
>  scripts/qapi.py          | 12 +++++++++
>  4 files changed, 62 insertions(+), 64 deletions(-)
>
> diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
> index 1d3c0d5..713aa0b 100644
> --- a/scripts/qapi-commands.py
> +++ b/scripts/qapi-commands.py
> @@ -25,17 +25,6 @@ def gen_command_decl(name, arg_type, ret_type):
>                   params=gen_params(arg_type, 'Error **errp'))
>
>
> -def gen_err_check(err):
> -    if not err:
> -        return ''
> -    return mcgen('''
> -    if (%(err)s) {
> -        goto out;
> -    }
> -''',
> -                 err=err)
> -
> -
>  def gen_call(name, arg_type, ret_type):
>      ret = ''
>
> @@ -56,7 +45,7 @@ def gen_call(name, arg_type, ret_type):
>  ''',
>                  c_name=c_name(name), args=argstr, lhs=lhs)
>      if ret_type:
> -        ret += gen_err_check('err')
> +        ret += gen_err_check()
>          ret += mcgen('''
>
>      qmp_marshal_output_%(c_name)s(retval, ret, &err);
> @@ -133,7 +122,7 @@ def gen_marshal_input_visit(arg_type, dealloc=False):
>  ''',
>                           c_name=c_name(memb.name), name=memb.name,
>                           errp=errparg)
> -            ret += gen_err_check(errarg)
> +            ret += gen_err_check(err=errarg)
>              ret += mcgen('''
>      if (has_%(c_name)s) {
>  ''',
> @@ -144,7 +133,7 @@ def gen_marshal_input_visit(arg_type, dealloc=False):
>  ''',
>                       c_name=c_name(memb.name), name=memb.name,
>                       c_type=memb.type.c_name(), errp=errparg)
> -        ret += gen_err_check(errarg)
> +        ret += gen_err_check(err=errarg)
>          if memb.optional:
>              pop_indent()
>              ret += mcgen('''
> @@ -159,7 +148,7 @@ def gen_marshal_input_visit(arg_type, dealloc=False):
>
>
>  def gen_marshal_output(ret_type):
> -    return mcgen('''
> +    ret = mcgen('''
>
>  static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject 
> **ret_out, Error **errp)
>  {
> @@ -170,9 +159,10 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s 
> ret_in, QObject **ret_out,
>
>      v = qmp_output_get_visitor(qov);
>      visit_type_%(c_name)s(v, &ret_in, "unused", &err);
> -    if (err) {
> -        goto out;
> -    }
> +''',
> +                c_type=ret_type.c_type(), c_name=ret_type.c_name())
> +    ret += gen_err_check()
> +    ret += mcgen('''
>      *ret_out = qmp_output_get_qobject(qov);
>
>   out:

Here's a case that becomes more verbose, so it's not just comment
duplication.  Also becomes a bit harder to read, I think.

> @@ -184,7 +174,8 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s 
> ret_in, QObject **ret_out,
>      qapi_dealloc_visitor_cleanup(qdv);
>  }
>  ''',
> -                 c_type=ret_type.c_type(), c_name=ret_type.c_name())
> +                 c_name=ret_type.c_name())
> +    return ret
>
>
>  def gen_marshal_proto(name):
> diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
> index b43bbc2..bbc6169 100644
> --- a/scripts/qapi-event.py
> +++ b/scripts/qapi-event.py
> @@ -68,12 +68,10 @@ def gen_event_send(name, arg_type):
>
>      /* Fake visit, as if all members are under a structure */
>      visit_start_struct(v, NULL, "", "%(name)s", 0, &err);
> -    if (err) {
> -        goto out;
> -    }
> -
>  ''',
>                       name=name)
> +        ret += gen_err_check()
> +        ret += '\n'
>
>          for memb in arg_type.members:
>              if memb.optional:

This one gets marginally shorter, but hardly simpler.

> @@ -91,14 +89,12 @@ def gen_event_send(name, arg_type):
>
>              ret += mcgen('''
>      visit_type_%(c_type)s(v, %(cast)s&%(c_name)s, "%(name)s", &err);
> -    if (err) {
> -        goto out;
> -    }
>  ''',
>                           cast=cast,
>                           c_name=c_name(memb.name),
>                           c_type=memb.type.c_name(),
>                           name=memb.name)
> +            ret += gen_err_check()
>
>              if memb.optional:
>                  pop_indent()
> @@ -109,9 +105,9 @@ def gen_event_send(name, arg_type):
>          ret += mcgen('''
>
>      visit_end_struct(v, &err);
> -    if (err) {
> -        goto out;
> -    }
> +''')
> +        ret += gen_err_check()
> +        ret += mcgen('''
>
>      obj = qmp_output_get_qobject(qov);
>      g_assert(obj != NULL);
> diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
> index 7ce8616..fec07ad 100644
> --- a/scripts/qapi-visit.py
> +++ b/scripts/qapi-visit.py
> @@ -81,11 +81,9 @@ static void visit_type_%(c_name)s_fields(Visitor *v, 
> %(c_name)s **obj, Error **e
>      if base:
>          ret += mcgen('''
>      visit_type_implicit_%(c_type)s(v, &(*obj)->%(c_name)s, &err);
> -    if (err) {
> -        goto out;
> -    }
>  ''',
>                       c_type=base.c_name(), c_name=c_name('base'))
> +        ret += gen_err_check()
>
>      for memb in members:
>          if memb.optional:
> @@ -107,11 +105,7 @@ static void visit_type_%(c_name)s_fields(Visitor *v, 
> %(c_name)s **obj, Error **e
>              ret += mcgen('''
>      }
>  ''')
> -        ret += mcgen('''
> -    if (err) {
> -        goto out;
> -    }
> -''')
> +        ret += gen_err_check()
>
>      if re.search('^ *goto out;', ret, re.MULTILINE):
>          ret += mcgen('''
> @@ -154,7 +148,7 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
> const char *name, Error
>
>
>  def gen_visit_list(name, element_type):
> -    return mcgen('''
> +    ret = mcgen('''
>
>  void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, 
> Error **errp)
>  {
> @@ -162,9 +156,10 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
> const char *name, Error
>      GenericList *i, **prev;
>
>      visit_start_list(v, name, &err);
> -    if (err) {
> -        goto out;
> -    }
> +''',
> +                c_name=c_name(name), c_elt_type=element_type.c_name())
> +    ret += gen_err_check()
> +    ret += mcgen('''
>
>      for (prev = (GenericList **)obj;
>           !err && (i = visit_next_list(v, prev, &err)) != NULL;
> @@ -181,6 +176,7 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
> const char *name, Error
>  }
>  ''',
>                   c_name=c_name(name), c_elt_type=element_type.c_name())
> +    return ret
>
>
>  def gen_visit_enum(name):
> @@ -202,16 +198,17 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s 
> **obj, const char *name, Error
>      Error *err = NULL;
>
>      visit_start_implicit_struct(v, (void**) obj, sizeof(%(c_name)s), &err);
> -    if (err) {
> -        goto out;
> -    }
> +''',
> +                c_name=c_name(name))
> +    ret += gen_err_check()
> +    ret += mcgen('''
>      visit_get_next_type(v, (int*) &(*obj)->kind, %(c_name)s_qtypes, name, 
> &err);
> -    if (err) {
> -        goto out_obj;
> -    }
> +''',
> +                 c_name=c_name(name))
> +    ret += gen_err_check(label='out_obj')
> +    ret += mcgen('''
>      switch ((*obj)->kind) {
> -''',
> -                c_name=c_name(name))
> +''')
>
>      for var in variants.variants:
>          ret += mcgen('''
> @@ -259,23 +256,21 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s 
> **obj, const char *name, Error
>      Error *err = NULL;
>
>      visit_start_struct(v, (void **)obj, "%(name)s", name, 
> sizeof(%(c_name)s), &err);
> -    if (err) {
> -        goto out;
> -    }
> +''',
> +                 c_name=c_name(name), name=name)
> +    ret += gen_err_check()
> +    ret += mcgen('''
>      if (!*obj) {
>          goto out_obj;
>      }
> -''',
> -                 c_name=c_name(name), name=name)
> +''')
>
>      if base:
>          ret += mcgen('''
>      visit_type_%(c_name)s_fields(v, obj, &err);
> -    if (err) {
> -        goto out_obj;
> -    }
>  ''',
>                       c_name=c_name(name))
> +        ret += gen_err_check(label='out_obj')
>
>      tag_key = variants.tag_member.name
>      if not variants.tag_name:
> @@ -283,13 +278,6 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
> const char *name, Error
>          tag_key = 'type'
>      ret += mcgen('''
>      visit_type_%(c_type)s(v, &(*obj)->%(c_name)s, "%(name)s", &err);
> -    if (err) {
> -        goto out_obj;
> -    }
> -    if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
> -        goto out_obj;
> -    }
> -    switch ((*obj)->%(c_name)s) {
>  ''',
>                   c_type=variants.tag_member.type.c_name(),
>                   # TODO ugly special case for simple union
> @@ -297,6 +285,17 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, 
> const char *name, Error
>                   # it, then: c_name=c_name(variants.tag_member.name)
>                   c_name=c_name(variants.tag_name or 'kind'),
>                   name=tag_key)
> +    ret += gen_err_check(label='out_obj')
> +    ret += mcgen('''
> +    if (!visit_start_union(v, !!(*obj)->data, &err) || err) {
> +        goto out_obj;
> +    }
> +    switch ((*obj)->%(c_name)s) {
> +''',
> +                 # TODO ugly special case for simple union
> +                 # Use same tag name in C as on the wire to get rid of
> +                 # it, then: c_name=c_name(variants.tag_member.name)
> +                 c_name=c_name(variants.tag_name or 'kind'))
>
>      for var in variants.variants:
>          # TODO ugly special case for simple union

Here's the duplicated comment.  It's a TODO, not a FIXME.

> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 4825e62..0593b71 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1536,6 +1536,18 @@ def gen_params(arg_type, extra):
>          ret += sep + extra
>      return ret
>
> +
> +def gen_err_check(err='err', label='out'):
> +    if not err:
> +        return ''
> +    return mcgen('''
> +    if (%(err)s) {
> +        goto %(label)s;
> +    }
> +''',
> +                 err=err, label=label)
> +
> +
>  #
>  # Common command line parsing
>  #

I don't know.  Could be worthwhile if it really makes further work
easier.

To really cut the verbosity, I figure we'd have to do something more
radical, like having cgen() recognize a (short!) pattern and replace it
with a full-blown error check.  Not sure that's actually a good idea,
though :)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]