summaryrefslogtreecommitdiffstats
path: root/scripts/qapi.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/qapi.py')
-rw-r--r--scripts/qapi.py227
1 files changed, 139 insertions, 88 deletions
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 38c808e256..0ebea945bb 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -2,14 +2,17 @@
# QAPI helper library
#
# Copyright IBM, Corp. 2011
+# Copyright (c) 2013 Red Hat Inc.
#
# Authors:
# Anthony Liguori <aliguori@us.ibm.com>
+# Markus Armbruster <armbru@redhat.com>
#
# This work is licensed under the terms of the GNU GPLv2.
# See the COPYING.LIB file in the top-level directory.
from ordereddict import OrderedDict
+import sys
builtin_types = [
'str', 'int', 'number', 'bool',
@@ -32,99 +35,147 @@ builtin_type_qtypes = {
'uint64': 'QTYPE_QINT',
}
-def tokenize(data):
- while len(data):
- ch = data[0]
- data = data[1:]
- if ch in ['{', '}', ':', ',', '[', ']']:
- yield ch
- elif ch in ' \n':
- None
- elif ch == "'":
- string = ''
- esc = False
- while True:
- if (data == ''):
- raise Exception("Mismatched quotes")
- ch = data[0]
- data = data[1:]
- if esc:
- string += ch
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == "'":
- break
- else:
- string += ch
- yield string
-
-def parse(tokens):
- if tokens[0] == '{':
- ret = OrderedDict()
- tokens = tokens[1:]
- while tokens[0] != '}':
- key = tokens[0]
- tokens = tokens[1:]
-
- tokens = tokens[1:] # :
-
- value, tokens = parse(tokens)
-
- if tokens[0] == ',':
- tokens = tokens[1:]
-
- ret[key] = value
- tokens = tokens[1:]
- return ret, tokens
- elif tokens[0] == '[':
- ret = []
- tokens = tokens[1:]
- while tokens[0] != ']':
- value, tokens = parse(tokens)
- if tokens[0] == ',':
- tokens = tokens[1:]
- ret.append(value)
- tokens = tokens[1:]
- return ret, tokens
- else:
- return tokens[0], tokens[1:]
-
-def evaluate(string):
- return parse(map(lambda x: x, tokenize(string)))[0]
-
-def get_expr(fp):
- expr = ''
-
- for line in fp:
- if line.startswith('#') or line == '\n':
- continue
-
- if line.startswith(' '):
- expr += line
- elif expr:
- yield expr
- expr = line
+class QAPISchemaError(Exception):
+ def __init__(self, schema, msg):
+ self.fp = schema.fp
+ self.msg = msg
+ self.line = self.col = 1
+ for ch in schema.src[0:schema.pos]:
+ if ch == '\n':
+ self.line += 1
+ self.col = 1
+ elif ch == '\t':
+ self.col = (self.col + 7) % 8 + 1
+ else:
+ self.col += 1
+
+ def __str__(self):
+ return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
+
+class QAPISchema:
+
+ def __init__(self, fp):
+ self.fp = fp
+ self.src = fp.read()
+ if self.src == '' or self.src[-1] != '\n':
+ self.src += '\n'
+ self.cursor = 0
+ self.exprs = []
+ self.accept()
+
+ while self.tok != None:
+ self.exprs.append(self.get_expr(False))
+
+ def accept(self):
+ while True:
+ self.tok = self.src[self.cursor]
+ self.pos = self.cursor
+ self.cursor += 1
+ self.val = None
+
+ if self.tok == '#':
+ self.cursor = self.src.find('\n', self.cursor)
+ elif self.tok in ['{', '}', ':', ',', '[', ']']:
+ return
+ elif self.tok == "'":
+ string = ''
+ esc = False
+ while True:
+ ch = self.src[self.cursor]
+ self.cursor += 1
+ if ch == '\n':
+ raise QAPISchemaError(self,
+ 'Missing terminating "\'"')
+ if esc:
+ string += ch
+ esc = False
+ elif ch == "\\":
+ esc = True
+ elif ch == "'":
+ self.val = string
+ return
+ else:
+ string += ch
+ elif self.tok == '\n':
+ if self.cursor == len(self.src):
+ self.tok = None
+ return
+ elif not self.tok.isspace():
+ raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
+
+ def get_members(self):
+ expr = OrderedDict()
+ if self.tok == '}':
+ self.accept()
+ return expr
+ if self.tok != "'":
+ raise QAPISchemaError(self, 'Expected string or "}"')
+ while True:
+ key = self.val
+ self.accept()
+ if self.tok != ':':
+ raise QAPISchemaError(self, 'Expected ":"')
+ self.accept()
+ expr[key] = self.get_expr(True)
+ if self.tok == '}':
+ self.accept()
+ return expr
+ if self.tok != ',':
+ raise QAPISchemaError(self, 'Expected "," or "}"')
+ self.accept()
+ if self.tok != "'":
+ raise QAPISchemaError(self, 'Expected string')
+
+ def get_values(self):
+ expr = []
+ if self.tok == ']':
+ self.accept()
+ return expr
+ if not self.tok in [ '{', '[', "'" ]:
+ raise QAPISchemaError(self, 'Expected "{", "[", "]" or string')
+ while True:
+ expr.append(self.get_expr(True))
+ if self.tok == ']':
+ self.accept()
+ return expr
+ if self.tok != ',':
+ raise QAPISchemaError(self, 'Expected "," or "]"')
+ self.accept()
+
+ def get_expr(self, nested):
+ if self.tok != '{' and not nested:
+ raise QAPISchemaError(self, 'Expected "{"')
+ if self.tok == '{':
+ self.accept()
+ expr = self.get_members()
+ elif self.tok == '[':
+ self.accept()
+ expr = self.get_values()
+ elif self.tok == "'":
+ expr = self.val
+ self.accept()
else:
- expr += line
-
- if expr:
- yield expr
+ raise QAPISchemaError(self, 'Expected "{", "[" or string')
+ return expr
def parse_schema(fp):
+ try:
+ schema = QAPISchema(fp)
+ except QAPISchemaError as e:
+ print >>sys.stderr, e
+ exit(1)
+
exprs = []
- for expr in get_expr(fp):
- expr_eval = evaluate(expr)
-
- if expr_eval.has_key('enum'):
- add_enum(expr_eval['enum'])
- elif expr_eval.has_key('union'):
- add_union(expr_eval)
- add_enum('%sKind' % expr_eval['union'])
- elif expr_eval.has_key('type'):
- add_struct(expr_eval)
- exprs.append(expr_eval)
+ for expr in schema.exprs:
+ if expr.has_key('enum'):
+ add_enum(expr['enum'])
+ elif expr.has_key('union'):
+ add_union(expr)
+ add_enum('%sKind' % expr['union'])
+ elif expr.has_key('type'):
+ add_struct(expr)
+ exprs.append(expr)
return exprs