|
@@ -50,6 +50,15 @@ def __init__(self, schema, msg):
|
|
def __str__(self):
|
|
def __str__(self):
|
|
return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
|
|
return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
|
|
|
|
|
|
|
|
+class QAPIExprError(Exception):
|
|
|
|
+ def __init__(self, expr_info, msg):
|
|
|
|
+ self.fp = expr_info['fp']
|
|
|
|
+ self.line = expr_info['line']
|
|
|
|
+ self.msg = msg
|
|
|
|
+
|
|
|
|
+ def __str__(self):
|
|
|
|
+ return "%s:%s: %s" % (self.fp.name, self.line, self.msg)
|
|
|
|
+
|
|
class QAPISchema:
|
|
class QAPISchema:
|
|
|
|
|
|
def __init__(self, fp):
|
|
def __init__(self, fp):
|
|
@@ -64,7 +73,10 @@ def __init__(self, fp):
|
|
self.accept()
|
|
self.accept()
|
|
|
|
|
|
while self.tok != None:
|
|
while self.tok != None:
|
|
- self.exprs.append(self.get_expr(False))
|
|
|
|
|
|
+ expr_info = {'fp': fp, 'line': self.line}
|
|
|
|
+ expr_elem = {'expr': self.get_expr(False),
|
|
|
|
+ 'info': expr_info}
|
|
|
|
+ self.exprs.append(expr_elem)
|
|
|
|
|
|
def accept(self):
|
|
def accept(self):
|
|
while True:
|
|
while True:
|
|
@@ -162,6 +174,71 @@ def get_expr(self, nested):
|
|
raise QAPISchemaError(self, 'Expected "{", "[" or string')
|
|
raise QAPISchemaError(self, 'Expected "{", "[" or string')
|
|
return expr
|
|
return expr
|
|
|
|
|
|
|
|
+def find_base_fields(base):
|
|
|
|
+ base_struct_define = find_struct(base)
|
|
|
|
+ if not base_struct_define:
|
|
|
|
+ return None
|
|
|
|
+ return base_struct_define['data']
|
|
|
|
+
|
|
|
|
+def check_union(expr, expr_info):
|
|
|
|
+ name = expr['union']
|
|
|
|
+ base = expr.get('base')
|
|
|
|
+ discriminator = expr.get('discriminator')
|
|
|
|
+ members = expr['data']
|
|
|
|
+
|
|
|
|
+ # If the object has a member 'base', its value must name a complex type.
|
|
|
|
+ if base:
|
|
|
|
+ base_fields = find_base_fields(base)
|
|
|
|
+ if not base_fields:
|
|
|
|
+ raise QAPIExprError(expr_info,
|
|
|
|
+ "Base '%s' is not a valid type"
|
|
|
|
+ % base)
|
|
|
|
+
|
|
|
|
+ # If the union object has no member 'discriminator', it's an
|
|
|
|
+ # ordinary union.
|
|
|
|
+ if not discriminator:
|
|
|
|
+ enum_define = None
|
|
|
|
+
|
|
|
|
+ # Else if the value of member 'discriminator' is {}, it's an
|
|
|
|
+ # anonymous union.
|
|
|
|
+ elif discriminator == {}:
|
|
|
|
+ enum_define = None
|
|
|
|
+
|
|
|
|
+ # Else, it's a flat union.
|
|
|
|
+ else:
|
|
|
|
+ # The object must have a member 'base'.
|
|
|
|
+ if not base:
|
|
|
|
+ raise QAPIExprError(expr_info,
|
|
|
|
+ "Flat union '%s' must have a base field"
|
|
|
|
+ % name)
|
|
|
|
+ # The value of member 'discriminator' must name a member of the
|
|
|
|
+ # base type.
|
|
|
|
+ discriminator_type = base_fields.get(discriminator)
|
|
|
|
+ if not discriminator_type:
|
|
|
|
+ raise QAPIExprError(expr_info,
|
|
|
|
+ "Discriminator '%s' is not a member of base "
|
|
|
|
+ "type '%s'"
|
|
|
|
+ % (discriminator, base))
|
|
|
|
+ enum_define = find_enum(discriminator_type)
|
|
|
|
+
|
|
|
|
+ # Check every branch
|
|
|
|
+ for (key, value) in members.items():
|
|
|
|
+ # If this named member's value names an enum type, then all members
|
|
|
|
+ # of 'data' must also be members of the enum type.
|
|
|
|
+ if enum_define and not key in enum_define['enum_values']:
|
|
|
|
+ raise QAPIExprError(expr_info,
|
|
|
|
+ "Discriminator value '%s' is not found in "
|
|
|
|
+ "enum '%s'" %
|
|
|
|
+ (key, enum_define["enum_name"]))
|
|
|
|
+ # Todo: add checking for values. Key is checked as above, value can be
|
|
|
|
+ # also checked here, but we need more functions to handle array case.
|
|
|
|
+
|
|
|
|
+def check_exprs(schema):
|
|
|
|
+ for expr_elem in schema.exprs:
|
|
|
|
+ expr = expr_elem['expr']
|
|
|
|
+ if expr.has_key('union'):
|
|
|
|
+ check_union(expr, expr_elem['info'])
|
|
|
|
+
|
|
def parse_schema(fp):
|
|
def parse_schema(fp):
|
|
try:
|
|
try:
|
|
schema = QAPISchema(fp)
|
|
schema = QAPISchema(fp)
|
|
@@ -171,7 +248,8 @@ def parse_schema(fp):
|
|
|
|
|
|
exprs = []
|
|
exprs = []
|
|
|
|
|
|
- for expr in schema.exprs:
|
|
|
|
|
|
+ for expr_elem in schema.exprs:
|
|
|
|
+ expr = expr_elem['expr']
|
|
if expr.has_key('enum'):
|
|
if expr.has_key('enum'):
|
|
add_enum(expr['enum'], expr['data'])
|
|
add_enum(expr['enum'], expr['data'])
|
|
elif expr.has_key('union'):
|
|
elif expr.has_key('union'):
|
|
@@ -181,6 +259,12 @@ def parse_schema(fp):
|
|
add_struct(expr)
|
|
add_struct(expr)
|
|
exprs.append(expr)
|
|
exprs.append(expr)
|
|
|
|
|
|
|
|
+ try:
|
|
|
|
+ check_exprs(schema)
|
|
|
|
+ except QAPIExprError, e:
|
|
|
|
+ print >>sys.stderr, e
|
|
|
|
+ exit(1)
|
|
|
|
+
|
|
return exprs
|
|
return exprs
|
|
|
|
|
|
def parse_args(typeinfo):
|
|
def parse_args(typeinfo):
|