diff mbox

[v4,03/10] qapi: Make c_type() more OO-like

Message ID 1457194595-16189-4-git-send-email-eblake@redhat.com
State New
Headers show

Commit Message

Eric Blake March 5, 2016, 4:16 p.m. UTC
QAPISchemaType.c_type() was a bit awkward.  Rather than having two
optional orthogonal boolean flags that should never both be true,
and where all callers should pass a compile-time constant (well,
our use of is_unboxed wasn't constant, but a future patch is about
to remove the special case for simple unions, so we can live with
the churn of refactoring the code in the meantime), the more
object-oriented approach uses different method names that can be
overridden as needed, and which convey the intent by the method
name.  The caller just makes sure to use the right variant, rather
than having to worry about boolean flags.

It requires slightly more Python, but is arguably easier to read.

Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>

---
v4: hoist earlier in series, rework simple union hack in qapi-types,
improve docs
[no v3]
v2: no change
---
 scripts/qapi.py       | 39 ++++++++++++++++++++++++++++++---------
 scripts/qapi-types.py |  7 +++++--
 2 files changed, 35 insertions(+), 11 deletions(-)

Comments

Markus Armbruster March 8, 2016, 10:54 a.m. UTC | #1
Eric Blake <eblake@redhat.com> writes:

> QAPISchemaType.c_type() was a bit awkward.  Rather than having two
> optional orthogonal boolean flags that should never both be true,
> and where all callers should pass a compile-time constant (well,
> our use of is_unboxed wasn't constant, but a future patch is about
> to remove the special case for simple unions, so we can live with
> the churn of refactoring the code in the meantime), the more
> object-oriented approach uses different method names that can be
> overridden as needed, and which convey the intent by the method
> name.  The caller just makes sure to use the right variant, rather
> than having to worry about boolean flags.
>
> It requires slightly more Python, but is arguably easier to read.

The second sentence is rather long.  Suggest:

    QAPISchemaType.c_type() is a bit awkward: it takes two optional
    boolean flags is_param and is_unboxed that should never both be
    true.

    Add a new method for each of the flags, and drop the flags from
    c_type().

    Most calls pass no flags.  They remain unchanged.

    One call passes is_param=True.  Call new .c_param_type() instead.

    One call passes is_unboxed=True except for simple union types.  This
    is actually an ugly special case that should go away soon.  Until
    then, we now have to call either .c_type() or the new
    .c_unboxed_type().  Tolerable.

> Suggested-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Eric Blake <eblake@redhat.com>

Patch looks good.
Eric Blake March 8, 2016, 3:50 p.m. UTC | #2
On 03/08/2016 03:54 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> QAPISchemaType.c_type() was a bit awkward.  Rather than having two
>> optional orthogonal boolean flags that should never both be true,
>> and where all callers should pass a compile-time constant (well,
>> our use of is_unboxed wasn't constant, but a future patch is about
>> to remove the special case for simple unions, so we can live with
>> the churn of refactoring the code in the meantime), the more
>> object-oriented approach uses different method names that can be
>> overridden as needed, and which convey the intent by the method
>> name.  The caller just makes sure to use the right variant, rather
>> than having to worry about boolean flags.
>>
>> It requires slightly more Python, but is arguably easier to read.
> 
> The second sentence is rather long.  Suggest:
> 
>     QAPISchemaType.c_type() is a bit awkward: it takes two optional
>     boolean flags is_param and is_unboxed that should never both be
>     true.
> 
>     Add a new method for each of the flags, and drop the flags from
>     c_type().
> 
>     Most calls pass no flags.  They remain unchanged.
> 
>     One call passes is_param=True.  Call new .c_param_type() instead.
> 
>     One call passes is_unboxed=True except for simple union types.  This
>     is actually an ugly special case that should go away soon.  Until
>     then, we now have to call either .c_type() or the new
>     .c_unboxed_type().  Tolerable.

Yes, that works for me.

> 
>> Suggested-by: Markus Armbruster <armbru@redhat.com>
>> Signed-off-by: Eric Blake <eblake@redhat.com>
> 
> Patch looks good.
>
diff mbox

Patch

diff --git a/scripts/qapi.py b/scripts/qapi.py
index dc26ef9..b1b87ee 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -822,8 +822,18 @@  class QAPISchemaVisitor(object):


 class QAPISchemaType(QAPISchemaEntity):
-    def c_type(self, is_param=False, is_unboxed=False):
-        return c_name(self.name) + pointer_suffix
+    # Return the C type for common use.
+    # For the types we commonly box, this is a pointer type.
+    def c_type(self):
+        pass
+
+    # Return the C type to be used in a parameter list.
+    def c_param_type(self):
+        return self.c_type()
+
+    # Return the C type to be used where we suppress boxing.
+    def c_unboxed_type(self):
+        return self.c_type()

     def c_null(self):
         return 'NULL'
@@ -855,8 +865,11 @@  class QAPISchemaBuiltinType(QAPISchemaType):
     def c_name(self):
         return self.name

-    def c_type(self, is_param=False, is_unboxed=False):
-        if is_param and self.name == 'str':
+    def c_type(self):
+        return self._c_type_name
+
+    def c_param_type(self):
+        if self.name == 'str':
             return 'const ' + self._c_type_name
         return self._c_type_name

@@ -889,7 +902,7 @@  class QAPISchemaEnumType(QAPISchemaType):
         # See QAPISchema._make_implicit_enum_type()
         return self.name.endswith('Kind')

-    def c_type(self, is_param=False, is_unboxed=False):
+    def c_type(self):
         return c_name(self.name)

     def member_names(self):
@@ -921,6 +934,9 @@  class QAPISchemaArrayType(QAPISchemaType):
     def is_implicit(self):
         return True

+    def c_type(self):
+        return c_name(self.name) + pointer_suffix
+
     def json_type(self):
         return 'array'

@@ -986,12 +1002,14 @@  class QAPISchemaObjectType(QAPISchemaType):
         assert not self.is_implicit()
         return QAPISchemaType.c_name(self)

-    def c_type(self, is_param=False, is_unboxed=False):
+    def c_type(self):
         assert not self.is_implicit()
-        if is_unboxed:
-            return c_name(self.name)
         return c_name(self.name) + pointer_suffix

+    def c_unboxed_type(self):
+        assert not self.is_implicit()
+        return c_name(self.name)
+
     def json_type(self):
         return 'object'

@@ -1140,6 +1158,9 @@  class QAPISchemaAlternateType(QAPISchemaType):
         for v in self.variants.variants:
             v.check_clash(self.info, seen)

+    def c_type(self):
+        return c_name(self.name) + pointer_suffix
+
     def json_type(self):
         return 'value'

@@ -1631,7 +1652,7 @@  def gen_params(arg_type, extra):
         sep = ', '
         if memb.optional:
             ret += 'bool has_%s, ' % c_name(memb.name)
-        ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
+        ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
     if extra:
         ret += sep + extra
     return ret
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 0306a88..f194bea 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -124,11 +124,14 @@  def gen_variants(variants):
     for var in variants.variants:
         # Ugly special case for simple union TODO get rid of it
         simple_union_type = var.simple_union_type()
-        typ = simple_union_type or var.type
+        if simple_union_type:
+            typ = simple_union_type.c_type()
+        else:
+            typ = var.type.c_unboxed_type()
         ret += mcgen('''
         %(c_type)s %(c_name)s;
 ''',
-                     c_type=typ.c_type(is_unboxed=not simple_union_type),
+                     c_type=typ,
                      c_name=c_name(var.name))

     ret += mcgen('''