qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PULL 12/12] qapi: Track location that created an implicit type
Date: Thu, 15 Oct 2015 09:51:45 +0200	[thread overview]
Message-ID: <1444895505-16067-13-git-send-email-armbru@redhat.com> (raw)
In-Reply-To: <1444895505-16067-1-git-send-email-armbru@redhat.com>

From: Eric Blake <eblake@redhat.com>

A future patch will move some error checking from the parser
to the various QAPISchema*.check() methods, which run only
after parsing completes.  It will thus be possible to create
a python instance representing an implicit QAPI type that
parses fine but will fail validation during check().  Since
all errors have to have an associated 'info' location, we
need a location to be associated with those implicit types.
The intuitive info to use is the location of the enclosing
entity that caused the creation of the implicit type.

Note that we do not anticipate builtin types being used in
an error message (as they are not part of the user's QAPI
input, the user can't cause a semantic error in their
behavior), so we exempt those types from requiring info, by
setting a flag to track the completion of _def_predefineds(),
and tracking that flag in _def_entity().

No change to the generated code.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1444710158-8723-13-git-send-email-eblake@redhat.com>
[Missing QAPISchemaArrayType.is_implicit() supplied]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 74 ++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 47 insertions(+), 27 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 471bbfc..9d53255 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -790,6 +790,11 @@ class QAPISchemaEntity(object):
     def __init__(self, name, info):
         assert isinstance(name, str)
         self.name = name
+        # For explicitly defined entities, info points to the (explicit)
+        # definition.  For builtins (and their arrays), info is None.
+        # For implicitly defined entities, info points to a place that
+        # triggered the implicit definition (there may be more than one
+        # such place).
         self.info = info
 
     def c_name(self):
@@ -903,6 +908,10 @@ class QAPISchemaEnumType(QAPISchemaType):
     def check(self, schema):
         assert len(set(self.values)) == len(self.values)
 
+    def is_implicit(self):
+        # See QAPISchema._make_implicit_enum_type()
+        return self.name[-4:] == 'Kind'
+
     def c_type(self, is_param=False):
         return c_name(self.name)
 
@@ -929,6 +938,9 @@ class QAPISchemaArrayType(QAPISchemaType):
         self.element_type = schema.lookup_type(self._element_type_name)
         assert self.element_type
 
+    def is_implicit(self):
+        return True
+
     def json_type(self):
         return 'array'
 
@@ -973,6 +985,10 @@ class QAPISchemaObjectType(QAPISchemaType):
             self.variants.check(schema, members, seen)
         self.members = members
 
+    def is_implicit(self):
+        # See QAPISchema._make_implicit_object_type()
+        return self.name[0] == ':'
+
     def c_name(self):
         assert not self.is_implicit()
         return QAPISchemaType.c_name(self)
@@ -1120,7 +1136,9 @@ class QAPISchema(object):
         try:
             self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
             self._entity_dict = {}
+            self._predefining = True
             self._def_predefineds()
+            self._predefining = False
             self._def_exprs()
             self.check()
         except (QAPISchemaError, QAPIExprError), err:
@@ -1128,6 +1146,8 @@ class QAPISchema(object):
             exit(1)
 
     def _def_entity(self, ent):
+        # Only the predefined types are allowed to not have info
+        assert ent.info or self._predefining
         assert ent.name not in self._entity_dict
         self._entity_dict[ent.name] = ent
 
@@ -1148,7 +1168,7 @@ class QAPISchema(object):
         # declared in the first file whether or not they are used.  Nicer
         # would be to use lazy instantiation, while figuring out how to
         # avoid compilation issues with multiple qapi-types.h.
-        self._make_array_type(name)
+        self._make_array_type(name, None)
 
     def _def_predefineds(self):
         for t in [('str',    'string',  'char' + pointer_suffix, 'NULL'),
@@ -1170,25 +1190,25 @@ class QAPISchema(object):
                                                           [], None)
         self._def_entity(self.the_empty_object_type)
 
-    def _make_implicit_enum_type(self, name, values):
+    def _make_implicit_enum_type(self, name, info, values):
         name = name + 'Kind'   # Use namespace reserved by add_name()
-        self._def_entity(QAPISchemaEnumType(name, None, values, None))
+        self._def_entity(QAPISchemaEnumType(name, info, values, None))
         return name
 
-    def _make_array_type(self, element_type):
+    def _make_array_type(self, element_type, info):
         # TODO fooList namespace is not reserved; user can create collisions,
         # or abuse our type system with ['fooList'] for 2D array
         name = element_type + 'List'
         if not self.lookup_type(name):
-            self._def_entity(QAPISchemaArrayType(name, None, element_type))
+            self._def_entity(QAPISchemaArrayType(name, info, element_type))
         return name
 
-    def _make_implicit_object_type(self, name, role, members):
+    def _make_implicit_object_type(self, name, info, role, members):
         if not members:
             return None
         name = ':obj-%s-%s' % (name, role)
         if not self.lookup_entity(name, QAPISchemaObjectType):
-            self._def_entity(QAPISchemaObjectType(name, None, None,
+            self._def_entity(QAPISchemaObjectType(name, info, None,
                                                   members, None))
         return name
 
@@ -1198,18 +1218,18 @@ class QAPISchema(object):
         prefix = expr.get('prefix')
         self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
 
-    def _make_member(self, name, typ):
+    def _make_member(self, name, typ, info):
         optional = False
         if name.startswith('*'):
             name = name[1:]
             optional = True
         if isinstance(typ, list):
             assert len(typ) == 1
-            typ = self._make_array_type(typ[0])
+            typ = self._make_array_type(typ[0], info)
         return QAPISchemaObjectTypeMember(name, typ, optional)
 
-    def _make_members(self, data):
-        return [self._make_member(key, value)
+    def _make_members(self, data, info):
+        return [self._make_member(key, value, info)
                 for (key, value) in data.iteritems()]
 
     def _def_struct_type(self, expr, info):
@@ -1217,22 +1237,22 @@ class QAPISchema(object):
         base = expr.get('base')
         data = expr['data']
         self._def_entity(QAPISchemaObjectType(name, info, base,
-                                              self._make_members(data),
+                                              self._make_members(data, info),
                                               None))
 
     def _make_variant(self, case, typ):
         return QAPISchemaObjectTypeVariant(case, typ)
 
-    def _make_simple_variant(self, case, typ):
+    def _make_simple_variant(self, case, typ, info):
         if isinstance(typ, list):
             assert len(typ) == 1
-            typ = self._make_array_type(typ[0])
-        typ = self._make_implicit_object_type(typ, 'wrapper',
-                                              [self._make_member('data', typ)])
+            typ = self._make_array_type(typ[0], info)
+        typ = self._make_implicit_object_type(
+            typ, info, 'wrapper', [self._make_member('data', typ, info)])
         return QAPISchemaObjectTypeVariant(case, typ)
 
-    def _make_implicit_tag(self, type_name, variants):
-        typ = self._make_implicit_enum_type(type_name,
+    def _make_implicit_tag(self, type_name, info, variants):
+        typ = self._make_implicit_enum_type(type_name, info,
                                             [v.name for v in variants])
         return QAPISchemaObjectTypeMember('type', typ, False)
 
@@ -1246,12 +1266,12 @@ class QAPISchema(object):
             variants = [self._make_variant(key, value)
                         for (key, value) in data.iteritems()]
         else:
-            variants = [self._make_simple_variant(key, value)
+            variants = [self._make_simple_variant(key, value, info)
                         for (key, value) in data.iteritems()]
-            tag_member = self._make_implicit_tag(name, variants)
+            tag_member = self._make_implicit_tag(name, info, variants)
         self._def_entity(
             QAPISchemaObjectType(name, info, base,
-                                 self._make_members(OrderedDict()),
+                                 self._make_members(OrderedDict(), info),
                                  QAPISchemaObjectTypeVariants(tag_name,
                                                               tag_member,
                                                               variants)))
@@ -1261,7 +1281,7 @@ class QAPISchema(object):
         data = expr['data']
         variants = [self._make_variant(key, value)
                     for (key, value) in data.iteritems()]
-        tag_member = self._make_implicit_tag(name, variants)
+        tag_member = self._make_implicit_tag(name, info, variants)
         self._def_entity(
             QAPISchemaAlternateType(name, info,
                                     QAPISchemaObjectTypeVariants(None,
@@ -1275,11 +1295,11 @@ class QAPISchema(object):
         gen = expr.get('gen', True)
         success_response = expr.get('success-response', True)
         if isinstance(data, OrderedDict):
-            data = self._make_implicit_object_type(name, 'arg',
-                                                   self._make_members(data))
+            data = self._make_implicit_object_type(
+                name, info, 'arg', self._make_members(data, info))
         if isinstance(rets, list):
             assert len(rets) == 1
-            rets = self._make_array_type(rets[0])
+            rets = self._make_array_type(rets[0], info)
         self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
                                            success_response))
 
@@ -1287,8 +1307,8 @@ class QAPISchema(object):
         name = expr['event']
         data = expr.get('data')
         if isinstance(data, OrderedDict):
-            data = self._make_implicit_object_type(name, 'arg',
-                                                   self._make_members(data))
+            data = self._make_implicit_object_type(
+                name, info, 'arg', self._make_members(data, info))
         self._def_entity(QAPISchemaEvent(name, info, data))
 
     def _def_exprs(self):
-- 
2.4.3

  parent reply	other threads:[~2015-10-15  7:52 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-15  7:51 [Qemu-devel] [PULL 00/12] QAPI patches Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 01/12] qapi: Fix regression with '-netdev help' Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 02/12] qapi: Use predicate callback to determine visit filtering Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 03/12] qapi: Prepare for errors during check() Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 04/12] qapi: Drop redundant alternate-good test Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 05/12] qapi: Move empty-enum to compile-time test Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 06/12] qapi: Drop redundant returns-int test Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 07/12] qapi: Drop redundant flat-union-reverse-define test Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 08/12] qapi: Drop redundant args-member-array test Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 09/12] qapi: Don't use info as witness of implicit object type Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 10/12] qapi: Lazy creation of array types Markus Armbruster
2015-10-15  7:51 ` [Qemu-devel] [PULL 11/12] qapi: Create simple union type member earlier Markus Armbruster
2015-10-15  7:51 ` Markus Armbruster [this message]
2015-10-16 17:41 ` [Qemu-devel] [PULL 00/12] QAPI patches 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=1444895505-16067-13-git-send-email-armbru@redhat.com \
    --to=armbru@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).