It will check whether base is set, whether discriminator is found
in base, whether the values specified are written correctly, and
whether all enum values are covered, when discriminator is a
pre-defined enum type. Exprs now have addtional info inside qapi.py
to form better error message.

Signed-off-by: Wenchao Xia <xiaw...@linux.vnet.ibm.com>
---
 scripts/qapi.py |   84 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index c504eb4..8af8cfd 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -50,6 +50,15 @@ class QAPISchemaError(Exception):
     def __str__(self):
         return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
 
+class QAPIExprError(Exception):
+    def __init__(self, expr_elem, msg):
+        self.fp = expr_elem['fp']
+        self.line = expr_elem['line']
+        self.msg = msg
+
+    def __str__(self):
+        return "%s:%s: %s" % (self.fp.name, self.line, self.msg)
+
 class QAPISchema:
 
     def __init__(self, fp):
@@ -64,7 +73,11 @@ class QAPISchema:
         self.accept()
 
         while self.tok != None:
-            self.exprs.append(self.get_expr(False))
+            line = self.line
+            expr_elem = {'expr': self.get_expr(False),
+                         'fp': fp,
+                         'line': line}
+            self.exprs.append(expr_elem)
 
     def accept(self):
         while True:
@@ -162,6 +175,66 @@ class QAPISchema:
             raise QAPISchemaError(self, 'Expected "{", "[" or string')
         return expr
 
+# This function can be used to check whether "base" is valid
+def find_base_fields(base):
+    base_struct_define = find_struct(base)
+    if not base_struct_define:
+        return None
+    return base_struct_define.get('data')
+
+# Return the discriminator enum define, if discriminator is specified in
+# @expr_elem["expr"] and it is a pre-defined enum type
+def discriminator_find_enum_define(expr_elem):
+    expr = expr_elem['expr']
+    discriminator = expr.get('discriminator')
+    base = expr.get('base')
+
+    # Only support discriminator when base present
+    if not (discriminator and base):
+        return None
+
+    base_fields = find_base_fields(base)
+
+    if not base_fields:
+        raise QAPIExprError(expr_elem,
+                            "Base '%s' is not a valid type"
+                            % base)
+
+    discriminator_type = base_fields.get(discriminator)
+
+    if not discriminator_type:
+        raise QAPIExprError(expr_elem,
+                            "Discriminator '%s' not found in schema"
+                            % discriminator)
+
+    return find_enum(discriminator_type)
+
+def check_union(expr_elem):
+    # If discriminator is specified and it is a pre-defined enum in schema,
+    # check its correctness
+    enum_define = discriminator_find_enum_define(expr_elem)
+    name = expr_elem['expr']['union']
+    members = expr_elem['expr']['data']
+    if enum_define:
+        for key in members:
+            if not key in enum_define['enum_values']:
+                raise QAPIExprError(expr_elem,
+                                    "Discriminator value '%s' is not found in "
+                                    "enum '%s'" %
+                                    (key, enum_define["enum_name"]))
+        for key in enum_define['enum_values']:
+            if not key in members:
+                raise QAPIExprError(expr_elem,
+                                    "Enum value '%s' is not covered by a "
+                                    "branch of union '%s'" %
+                                    (key, name))
+
+def check_exprs(schema):
+    for expr_elem in schema.exprs:
+        expr = expr_elem['expr']
+        if expr.has_key('union'):
+            check_union(expr_elem)
+
 def parse_schema(fp):
     try:
         schema = QAPISchema(fp)
@@ -171,7 +244,8 @@ def parse_schema(fp):
 
     exprs = []
 
-    for expr in schema.exprs:
+    for expr_elem in schema.exprs:
+        expr = expr_elem['expr']
         if expr.has_key('enum'):
             add_enum(expr['enum'], expr['data'])
         elif expr.has_key('union'):
@@ -181,6 +255,12 @@ def parse_schema(fp):
             add_struct(expr)
         exprs.append(expr)
 
+    try:
+        check_exprs(schema)
+    except QAPIExprError, e:
+        print >>sys.stderr, e
+        exit(1)
+
     return exprs
 
 def parse_args(typeinfo):
-- 
1.7.1


Reply via email to