From b1dc7fae2a95804948ba9eedca08d208cdd5f825 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 26 May 2010 12:19:58 +0200 Subject: Initial import of spice protocol description and demarshall generator The "spice.proto" file describes in detail the networking prototcol that spice uses and spice_codegen.py can parse this and generate demarshallers for such network messages. --- python_modules/spice_parser.py | 157 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 python_modules/spice_parser.py (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py new file mode 100644 index 0000000..65916b3 --- /dev/null +++ b/python_modules/spice_parser.py @@ -0,0 +1,157 @@ +from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \ + Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ + alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith + +import ptypes +import sys + +cvtInt = lambda toks: int(toks[0]) + +def parseVariableDef(toks): + t = toks[0][0] + pointer = toks[0][1] + name = toks[0][2] + array_size = toks[0][3] + attributes = toks[0][4] + + if array_size != None: + t = ptypes.ArrayType(t, array_size) + + if pointer != None: + t = ptypes.PointerType(t); + + return ptypes.Member(name, t, attributes) + +bnf = None +def SPICE_BNF(): + global bnf + + if not bnf: + + # punctuation + colon = Literal(":").suppress() + lbrace = Literal("{").suppress() + rbrace = Literal("}").suppress() + lbrack = Literal("[").suppress() + rbrack = Literal("]").suppress() + lparen = Literal("(").suppress() + rparen = Literal(")").suppress() + equals = Literal("=").suppress() + comma = Literal(",").suppress() + semi = Literal(";").suppress() + + # primitive types + int8_ = Keyword("int8").setParseAction(replaceWith(ptypes.int8)) + uint8_ = Keyword("uint8").setParseAction(replaceWith(ptypes.uint8)) + int16_ = Keyword("int16").setParseAction(replaceWith(ptypes.int16)) + uint16_ = Keyword("uint16").setParseAction(replaceWith(ptypes.uint16)) + int32_ = Keyword("int32").setParseAction(replaceWith(ptypes.int32)) + uint32_ = Keyword("uint32").setParseAction(replaceWith(ptypes.uint32)) + int64_ = Keyword("int64").setParseAction(replaceWith(ptypes.int64)) + uint64_ = Keyword("uint64").setParseAction(replaceWith(ptypes.uint64)) + + # keywords + channel_ = Keyword("channel") + enum32_ = Keyword("enum32").setParseAction(replaceWith(32)) + enum16_ = Keyword("enum16").setParseAction(replaceWith(16)) + enum8_ = Keyword("enum8").setParseAction(replaceWith(8)) + flags32_ = Keyword("flags32").setParseAction(replaceWith(32)) + flags16_ = Keyword("flags16").setParseAction(replaceWith(16)) + flags8_ = Keyword("flags8").setParseAction(replaceWith(8)) + channel_ = Keyword("channel") + server_ = Keyword("server") + client_ = Keyword("client") + protocol_ = Keyword("protocol") + typedef_ = Keyword("typedef") + struct_ = Keyword("struct") + message_ = Keyword("message") + image_size_ = Keyword("image_size") + bytes_ = Keyword("bytes") + cstring_ = Keyword("cstring") + switch_ = Keyword("switch") + default_ = Keyword("default") + case_ = Keyword("case") + + identifier = Word( alphas, alphanums + "_" ) + enumname = Word( alphanums + "_" ) + + integer = ( Combine( CaselessLiteral("0x") + Word( nums+"abcdefABCDEF" ) ) | + Word( nums+"+-", nums ) ).setName("int").setParseAction(cvtInt) + + typename = identifier.copy().setParseAction(lambda toks : ptypes.TypeRef(str(toks[0]))) + + # This is just normal "types", i.e. not channels or messages + typeSpec = Forward() + + attributeValue = integer ^ identifier + attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen)) + attributes = Group(ZeroOrMore(attribute)) + arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen) + arraySizeSpecBytes = Group(bytes_ + lparen + identifier + rparen) + arraySizeSpecCString = Group(cstring_ + lparen + rparen) + arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecBytes ^arraySizeSpecCString, default="") + rbrack + variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \ + .setParseAction(parseVariableDef) + + switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | case_.suppress() + identifier + colon)) + variableDef) \ + .setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1])) + switchBody = Group(switch_ + lparen + identifier + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \ + .setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) + messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody) + rbrace) + structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) + + # have to use longest match for type, in case a user-defined type name starts with a keyword type, like "channel_type" + typeSpec << ( structSpec ^ int8_ ^ uint8_ ^ int16_ ^ uint16_ ^ + int32_ ^ uint32_ ^ int64_ ^ uint64_ ^ + typename).setName("type") + + flagsBody = enumBody = Group(lbrace + delimitedList(Group (enumname + Optional(equals + integer))) + Optional(comma) + rbrace) + + messageSpec = Group(message_ + messageBody + attributes).setParseAction(lambda toks: ptypes.MessageType(None, toks[0][1], toks[0][2])) | typename + + channelParent = Optional(colon + typename, default=None) + channelMessage = Group(messageSpec + identifier + Optional(equals + integer, default=None) + semi) \ + .setParseAction(lambda toks: ptypes.ChannelMember(toks[0][1], toks[0][0], toks[0][2])) + channelBody = channelParent + Group(lbrace + ZeroOrMore( server_ + colon | client_ + colon | channelMessage) + rbrace) + + enum_ = (enum32_ | enum16_ | enum8_) + flags_ = (flags32_ | flags16_ | flags8_) + enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) + flagsDef = Group(flags_ + identifier + flagsBody + attributes - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) + messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3])) + channelDef = Group(channel_ + identifier + channelBody - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3])) + structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) + typedefDef = Group(typedef_ + identifier + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3])) + + definitions = typedefDef | structDef | enumDef | flagsDef | messageDef | channelDef + + protocolChannel = Group(typename + identifier + Optional(equals + integer, default=None) + semi) \ + .setParseAction(lambda toks: ptypes.ProtocolMember(toks[0][1], toks[0][0], toks[0][2])) + protocolDef = Group(protocol_ + identifier + Group(lbrace + ZeroOrMore(protocolChannel) + rbrace) + semi) \ + .setParseAction(lambda toks: ptypes.ProtocolType(toks[0][1], toks[0][2])) + + bnf = ZeroOrMore (definitions) + protocolDef + StringEnd() + + singleLineComment = "//" + restOfLine + bnf.ignore( singleLineComment ) + bnf.ignore( cStyleComment ) + + return bnf + + +def parse(filename): + try: + bnf = SPICE_BNF() + types = bnf.parseFile(filename) + except ParseException, err: + print >> sys.stderr, err.line + print >> sys.stderr, " "*(err.column-1) + "^" + print >> sys.stderr, err + return None + + for t in types: + t.resolve() + t.register() + protocol = types[-1] + return protocol + -- cgit From e42c910b5cb5e6de734064fb57832a6e73e34092 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Tue, 29 Jun 2010 21:42:59 +0200 Subject: Store SpicePath segment count rather than size Internally and in the network protocol (for the new version) we now store the actual number of segments rather than the size of the full segments array in bytes. This change consists of multiple changes to handle this: * Make the qxl parser calculate num_segments * Make the canvas stroke code handle the new SpicePath layout. * Fix up is_equal_path in red_worker.c for the new layout * replace multiple calls to spice_marshall_PathSegment with a single spice_marshall_Path call * Make the byte_size() array size handling do the conversion from network size to number of elements when marshalling/demarshalling. * Update the current spice protocol to send the segment count rather than the size * Update the old spice protocol to use the new byte_size functionallity to calculate the size sent and the number of elements recieved --- python_modules/spice_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index 65916b3..61ef458 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -87,7 +87,7 @@ def SPICE_BNF(): attribute = Group(Combine ("@" + identifier) + Optional(lparen + delimitedList(attributeValue) + rparen)) attributes = Group(ZeroOrMore(attribute)) arraySizeSpecImage = Group(image_size_ + lparen + integer + comma + identifier + comma + identifier + rparen) - arraySizeSpecBytes = Group(bytes_ + lparen + identifier + rparen) + arraySizeSpecBytes = Group(bytes_ + lparen + identifier + comma + identifier + rparen) arraySizeSpecCString = Group(cstring_ + lparen + rparen) arraySizeSpec = lbrack + Optional(identifier ^ integer ^ arraySizeSpecImage ^ arraySizeSpecBytes ^arraySizeSpecCString, default="") + rbrack variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \ -- cgit From 0ed056da99f2ee23da5600f76d5824c68918c1b5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 1 Jul 2010 17:55:33 +0200 Subject: Properly parse QXLImage to the new-world SpiceImage SpiceImage now replaces RedImage and has all image types in it. All image data are now chunked (and as such not copied when demarshalling). --- python_modules/spice_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index 61ef458..ac2da8d 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -95,7 +95,7 @@ def SPICE_BNF(): switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | case_.suppress() + identifier + colon)) + variableDef) \ .setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1])) - switchBody = Group(switch_ + lparen + identifier + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \ + switchBody = Group(switch_ + lparen + delimitedList(identifier,delim='.', combine=True) + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \ .setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) messageBody = structBody = Group(lbrace + ZeroOrMore(variableDef | switchBody) + rbrace) structSpec = Group(struct_ + identifier + structBody + attributes).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) -- cgit From 4702feb5b1958eeef9b4414a2fb7cac259394a52 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Mon, 19 Jul 2010 16:27:42 +0200 Subject: Don't send CursorHeader if cursor_flags is NONE --- python_modules/spice_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index ac2da8d..43e930c 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -93,7 +93,7 @@ def SPICE_BNF(): variableDef = Group(typeSpec + Optional("*", default=None) + identifier + Optional(arraySizeSpec, default=None) + attributes - semi) \ .setParseAction(parseVariableDef) - switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | case_.suppress() + identifier + colon)) + variableDef) \ + switchCase = Group(Group(OneOrMore(default_.setParseAction(replaceWith(None)) + colon | Group(case_.suppress() + Optional("!", default="") + identifier) + colon)) + variableDef) \ .setParseAction(lambda toks: ptypes.SwitchCase(toks[0][0], toks[0][1])) switchBody = Group(switch_ + lparen + delimitedList(identifier,delim='.', combine=True) + rparen + lbrace + Group(OneOrMore(switchCase)) + rbrace + identifier + attributes - semi) \ .setParseAction(lambda toks: ptypes.Switch(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) -- cgit From bbd93cdb6b26e475bc7772a6b0c239082adfc153 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Tue, 21 Jun 2011 13:20:33 +0200 Subject: python: remove c-ism trailing ; --- python_modules/spice_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index 43e930c..4c8a57a 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -18,7 +18,7 @@ def parseVariableDef(toks): t = ptypes.ArrayType(t, array_size) if pointer != None: - t = ptypes.PointerType(t); + t = ptypes.PointerType(t) return ptypes.Member(name, t, attributes) -- cgit From a11615f71391c1ef7e578eaec1c57fcd0f076420 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Thu, 19 May 2011 15:59:07 +0200 Subject: add check for pyparsing Check both in configure.ac (after checking if we need to rebuild the marshalling files) and in the python script using pyparsing (for people modifying .proto files in tarballs) --- python_modules/spice_parser.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index 4c8a57a..e20e8fc 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -1,6 +1,11 @@ -from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \ - Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ - alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith +try: + from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \ + Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ + alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith +except ImportError: + print "Module pyparsing not found." + exit(1) + import ptypes import sys -- cgit From ce59cc14167979a54f5846a59d58db132f4c6048 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 10 Jan 2012 15:03:38 +0000 Subject: Remove trailing blank lines Remove any blank lines at the end of all source files --- python_modules/spice_parser.py | 1 - 1 file changed, 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index e20e8fc..d0aabb0 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -159,4 +159,3 @@ def parse(filename): t.register() protocol = types[-1] return protocol - -- cgit From 0067c31bad1fadbfceba7014497374b9daf9a6a0 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Wed, 22 Jun 2011 13:23:47 +0200 Subject: allow attributes on channel elements in .proto files We want to be able to add an @ifdef annotation to optional messages For example, we want to compile in the smartcard messages only if libcacard is available --- python_modules/spice_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index d0aabb0..44456ab 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -124,7 +124,7 @@ def SPICE_BNF(): enumDef = Group(enum_ + identifier + enumBody + attributes - semi).setParseAction(lambda toks: ptypes.EnumType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) flagsDef = Group(flags_ + identifier + flagsBody + attributes - semi).setParseAction(lambda toks: ptypes.FlagsType(toks[0][0], toks[0][1], toks[0][2], toks[0][3])) messageDef = Group(message_ + identifier + messageBody + attributes - semi).setParseAction(lambda toks: ptypes.MessageType(toks[0][1], toks[0][2], toks[0][3])) - channelDef = Group(channel_ + identifier + channelBody - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3])) + channelDef = Group(channel_ + identifier + channelBody + attributes - semi).setParseAction(lambda toks: ptypes.ChannelType(toks[0][1], toks[0][2], toks[0][3], toks[0][4])) structDef = Group(struct_ + identifier + structBody + attributes - semi).setParseAction(lambda toks: ptypes.StructType(toks[0][1], toks[0][2], toks[0][3])) typedefDef = Group(typedef_ + identifier + typeSpec + attributes - semi).setParseAction(lambda toks: ptypes.TypeAlias(toks[0][1], toks[0][2], toks[0][3])) -- cgit From e919337980c45fb4bc907cf40cdd106fb8f32d92 Mon Sep 17 00:00:00 2001 From: Alexander Wauck Date: Tue, 31 Mar 2015 12:44:09 -0500 Subject: Make spice_codegen.py work on both Python 2 and 3 This is a new version of my previous patch that does not include six.py. It's still kind of big, but at least it's all spice-common changes now. There are also a few other fixes that Christophe brought to my attention. Note that six now needs to be installed on the system (python-six on Fedora and Debian, six on PyPI). This *should* be enough to make spice_codegen.py work on both Python 2 and Python 3. The major changes are as follows: * cStringIO.StringIO -> io.StringIO * str vs. unicode updates (io.StringIO doesn't like str) * integer division * foo.has_key(bar) -> bar in foo * import internal_thing -> from . import internal_thing * removed from __future__ import with_statement (might break Python 2.5?) * changed some lambdas to list comprehensions (done by 2to3) * cast some_dict.keys() to list where needed (e.g. for sorting) * use normal type names with isinstance instead of types.WhateverType Signed-off-by: Alexander Wauck --- python_modules/spice_parser.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index 44456ab..d60bb10 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -3,11 +3,12 @@ try: Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith except ImportError: - print "Module pyparsing not found." + six.print_("Module pyparsing not found.") exit(1) -import ptypes +from . import ptypes +import six import sys cvtInt = lambda toks: int(toks[0]) @@ -148,10 +149,10 @@ def parse(filename): try: bnf = SPICE_BNF() types = bnf.parseFile(filename) - except ParseException, err: - print >> sys.stderr, err.line - print >> sys.stderr, " "*(err.column-1) + "^" - print >> sys.stderr, err + except ParseException as err: + six.print_(err.line, file=sys.stderr) + six.print_(" "*(err.column-1) + "^", file=sys.stderr) + six.print_(err, file=sys.stderr) return None for t in types: -- cgit From 4a2a9966749c09465aa85a5fbd19cf7995d06f45 Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Tue, 21 Jul 2015 17:45:31 +0100 Subject: codegen: Import six module before first use The module is used in the initial try/except so make sure it is already imported. Signed-off-by: Frediano Ziglio --- python_modules/spice_parser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index d60bb10..80b559b 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -1,3 +1,5 @@ +import six + try: from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \ Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \ @@ -8,7 +10,6 @@ except ImportError: from . import ptypes -import six import sys cvtInt = lambda toks: int(toks[0]) -- cgit From 13aabda256b8a8342735b52fc3fb9e426f581dae Mon Sep 17 00:00:00 2001 From: Frediano Ziglio Date: Tue, 21 Jul 2015 17:45:35 +0100 Subject: codegen: Remove duplicate variable initialization Signed-off-by: Frediano Ziglio --- python_modules/spice_parser.py | 1 - 1 file changed, 1 deletion(-) (limited to 'python_modules/spice_parser.py') diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py index 80b559b..97af8b2 100644 --- a/python_modules/spice_parser.py +++ b/python_modules/spice_parser.py @@ -58,7 +58,6 @@ def SPICE_BNF(): uint64_ = Keyword("uint64").setParseAction(replaceWith(ptypes.uint64)) # keywords - channel_ = Keyword("channel") enum32_ = Keyword("enum32").setParseAction(replaceWith(32)) enum16_ = Keyword("enum16").setParseAction(replaceWith(16)) enum8_ = Keyword("enum8").setParseAction(replaceWith(8)) -- cgit