diff options
Diffstat (limited to 'python/qpid/spec010.py')
| -rw-r--r-- | python/qpid/spec010.py | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/python/qpid/spec010.py b/python/qpid/spec010.py new file mode 100644 index 0000000000..2d8bd6050d --- /dev/null +++ b/python/qpid/spec010.py @@ -0,0 +1,617 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import datatypes +from codec010 import StringCodec + +class Node: + + def __init__(self, children): + self.children = children + self.named = {} + self.docs = [] + self.rules = [] + + def register(self): + for ch in self.children: + ch.register(self) + + def resolve(self): + for ch in self.children: + ch.resolve() + + def __getitem__(self, name): + path = name.split(".", 1) + nd = self.named + for step in path: + nd = nd[step] + return nd + + def __iter__(self): + return iter(self.children) + +class Anonymous: + + def __init__(self, children): + self.children = children + + def register(self, node): + for ch in self.children: + ch.register(node) + + def resolve(self): + for ch in self.children: + ch.resolve() + +class Named: + + def __init__(self, name): + self.name = name + self.qname = None + + def register(self, node): + self.spec = node.spec + self.klass = node.klass + node.named[self.name] = self + if node.qname: + self.qname = "%s.%s" % (node.qname, self.name) + else: + self.qname = self.name + + def __str__(self): + return self.qname + + def __repr__(self): + return str(self) + +class Lookup: + + def lookup(self, name): + value = None + if self.klass: + try: + value = self.klass[name] + except KeyError: + pass + if not value: + value = self.spec[name] + return value + +class Coded: + + def __init__(self, code): + self.code = code + +class Constant(Named, Node): + + def __init__(self, name, value, children): + Named.__init__(self, name) + Node.__init__(self, children) + self.value = value + + def register(self, node): + Named.register(self, node) + node.constants.append(self) + Node.register(self) + +class Type(Named, Node): + + def __init__(self, name, children): + Named.__init__(self, name) + Node.__init__(self, children) + + def is_present(self, value): + return value != None + + def register(self, node): + Named.register(self, node) + node.types.append(self) + Node.register(self) + +class Primitive(Coded, Type): + + def __init__(self, name, code, fixed, variable, children): + Coded.__init__(self, code) + Type.__init__(self, name, children) + self.fixed = fixed + self.variable = variable + + def is_present(self, value): + if self.fixed == 0: + return value + else: + return Type.is_present(self, value) + + def encode(self, codec, value): + getattr(codec, "write_%s" % self.name)(value) + + def decode(self, codec): + return getattr(codec, "read_%s" % self.name)() + +class Domain(Type, Lookup): + + def __init__(self, name, type, children): + Type.__init__(self, name, children) + self.type = type + self.choices = {} + + def resolve(self): + self.type = self.lookup(self.type) + Node.resolve(self) + + def encode(self, codec, value): + self.type.encode(codec, value) + + def decode(self, codec): + return self.type.decode(codec) + +class Choice(Named, Node): + + def __init__(self, name, value, children): + Named.__init__(self, name) + Node.__init__(self, children) + self.value = value + + def register(self, node): + Named.register(self, node) + node.choices[self.value] = self + Node.register(self) + +class Composite(Type, Coded): + + def __init__(self, name, code, size, pack, children): + Coded.__init__(self, code) + Type.__init__(self, name, children) + self.fields = [] + self.size = size + self.pack = pack + + def new(self, args, kwargs): + if len(args) > len(self.fields): + raise TypeError("%s takes at most %s arguments (%s given)" % + (self.name, len(self.fields), len(self.args))) + + result = {"type": self} + + for a, f, in zip(args, self.fields): + result[f.name] = a + + for k, v in kwargs.items(): + f = self.named.get(k, None) + if f == None: + raise TypeError("%s got an unexpected keyword argument '%s'" % + (self.name, k)) + result[f.name] = v + + return datatypes.Struct(result) + + def decode(self, codec): + codec.read_size(self.size) + return self.decode_fields(codec) + + def decode_fields(self, codec): + flags = 0 + for i in range(self.pack): + flags |= (codec.read_uint8() << 8*i) + + result = {"type": self} + + for i in range(len(self.fields)): + f = self.fields[i] + if flags & (0x1 << i): + result[f.name] = f.type.decode(codec) + else: + result[f.name] = None + return datatypes.Struct(result) + + def encode(self, codec, value): + sc = StringCodec(self.spec) + self.encode_fields(sc, value) + codec.write_size(self.size, len(sc.encoded)) + codec.write(sc.encoded) + + def encode_fields(self, codec, value): + values = value.__dict__ + flags = 0 + for i in range(len(self.fields)): + f = self.fields[i] + if f.type.is_present(values.get(f.name, None)): + flags |= (0x1 << i) + for i in range(self.pack): + codec.write_uint8((flags >> 8*i) & 0xFF) + for i in range(len(self.fields)): + f = self.fields[i] + if flags & (0x1 << i): + f.type.encode(codec, values[f.name]) + +class Field(Named, Node, Lookup): + + def __init__(self, name, type, children): + Named.__init__(self, name) + Node.__init__(self, children) + self.type = type + self.exceptions = [] + + def register(self, node): + Named.register(self, node) + node.fields.append(self) + Node.register(self) + + def resolve(self): + self.type = self.lookup(self.type) + Node.resolve(self) + + def __str__(self): + return "%s: %s" % (self.qname, self.type.qname) + +class Struct(Composite): + + def register(self, node): + Composite.register(self, node) + self.spec.structs[self.code] = self + + def __str__(self): + fields = ",\n ".join(["%s: %s" % (f.name, f.type.qname) + for f in self.fields]) + return "%s {\n %s\n}" % (self.qname, fields) + +class Segment(Node): + + def register(self, node): + self.spec = node.spec + self.klass = node.klass + node.segments.append(self) + Node.register(self) + +class Instruction(Composite, Segment): + + def __init__(self, name, code, children): + Composite.__init__(self, name, code, 0, 2, children) + self.segment_type = None + self.track = None + self.handlers = [] + + def __str__(self): + return "%s(%s)" % (self.qname, ", ".join(["%s: %s" % (f.name, f.type.qname) + for f in self.fields])) + + def register(self, node): + Composite.register(self, node) + self.spec.instructions[self.qname.replace(".", "_")] = self + +class Control(Instruction): + + def __init__(self, name, code, children): + Instruction.__init__(self, name, code, children) + self.response = None + + def register(self, node): + Instruction.register(self, node) + node.controls.append(self) + self.spec.controls[self.code] = self + self.segment_type = self.spec["segment_type.control"].value + self.track = self.spec["track.control"].value + +class Command(Instruction): + + def __init__(self, name, code, children): + Instruction.__init__(self, name, code, children) + self.result = None + self.exceptions = [] + self.segments = [] + + def register(self, node): + Instruction.register(self, node) + node.commands.append(self) + self.header = self.spec["session.header"] + self.spec.commands[self.code] = self + self.segment_type = self.spec["segment_type.command"].value + self.track = self.spec["track.command"].value + + def decode(self, codec): + hdr = self.header.decode(codec) + args = Instruction.decode(self, codec) + result = {} + result.update(hdr.fields()) + result.update(args.fields()) + return datatypes.Struct(result) + + def encode(self, codec, cmd): + self.header.encode(codec, cmd) + Instruction.encode(self, codec, cmd) + +class Header(Segment): + + def __init__(self, children): + self.entries = [] + Segment.__init__(self, children) + +class Entry(Lookup): + + def __init__(self, type): + self.type = type + + def register(self, node): + self.spec = node.spec + self.klass = node.klass + node.entries.append(self) + + def resolve(self): + self.type = self.lookup(self.type) + +class Body(Segment): + + def resolve(self): pass + +class Class(Named, Coded, Node): + + def __init__(self, name, code, children): + Named.__init__(self, name) + Coded.__init__(self, code) + Node.__init__(self, children) + self.types = [] + self.controls = [] + self.commands = [] + + def register(self, node): + Named.register(self, node) + self.klass = self + node.classes.append(self) + Node.register(self) + +class Doc: + + def __init__(self, type, title, text): + self.type = type + self.title = title + self.text = text + + def register(self, node): + node.docs.append(self) + + def resolve(self): pass + +class Role(Named, Node): + + def __init__(self, name, children): + Named.__init__(self, name) + Node.__init__(self, children) + + def register(self, node): + Named.register(self, node) + Node.register(self) + +class Rule(Named, Node): + + def __init__(self, name, children): + Named.__init__(self, name) + Node.__init__(self, children) + + def register(self, node): + Named.register(self, node) + node.rules.append(self) + Node.register(self) + +class Exception(Named, Node): + + def __init__(self, name, error_code, children): + Named.__init__(self, name) + Node.__init__(self, children) + self.error_code = error_code + + def register(self, node): + Named.register(self, node) + node.exceptions.append(self) + Node.register(self) + +class Spec(Node): + + def __init__(self, major, minor, port, children): + Node.__init__(self, children) + self.major = major + self.minor = minor + self.port = port + self.constants = [] + self.classes = [] + self.types = [] + self.qname = None + self.spec = self + self.klass = None + self.instructions = {} + self.controls = {} + self.commands = {} + self.structs = {} + +class Implement: + + def __init__(self, handle): + self.handle = handle + + def register(self, node): + node.handlers.append(self.handle) + + def resolve(self): pass + +class Response(Node): + + def __init__(self, name, children): + Node.__init__(self, children) + self.name = name + + def register(self, node): + Node.register(self) + +class Result(Node, Lookup): + + def __init__(self, type, children): + self.type = type + Node.__init__(self, children) + + def register(self, node): + node.result = self + self.qname = node.qname + self.klass = node.klass + self.spec = node.spec + Node.register(self) + + def resolve(self): + self.type = self.lookup(self.type) + Node.resolve(self) + +import mllib + +def num(s): + if s: return int(s, 0) + +REPLACE = {" ": "_", "-": "_"} +KEYWORDS = {"global": "global_", + "return": "return_"} + +def id(name): + name = str(name) + for key, val in REPLACE.items(): + name = name.replace(key, val) + try: + name = KEYWORDS[name] + except KeyError: + pass + return name + +class Loader: + + def __init__(self): + self.class_code = 0 + + def code(self, nd): + c = num(nd["@code"]) + if c is None: + return None + else: + return c | (self.class_code << 8) + + def list(self, q): + result = [] + for nd in q: + result.append(nd.dispatch(self)) + return result + + def children(self, n): + return self.list(n.query["#tag"]) + + def data(self, d): + return d.data + + def do_amqp(self, a): + return Spec(num(a["@major"]), num(a["@minor"]), num(a["@port"]), + self.children(a)) + + def do_type(self, t): + return Primitive(id(t["@name"]), self.code(t), num(t["@fixed-width"]), + num(t["@variable-width"]), self.children(t)) + + def do_constant(self, c): + return Constant(id(c["@name"]), num(c["@value"]), self.children(c)) + + def do_domain(self, d): + return Domain(id(d["@name"]), id(d["@type"]), self.children(d)) + + def do_enum(self, e): + return Anonymous(self.children(e)) + + def do_choice(self, c): + return Choice(id(c["@name"]), num(c["@value"]), self.children(c)) + + def do_class(self, c): + code = num(c["@code"]) + self.class_code = code + children = self.children(c) + children += self.list(c.query["command/result/struct"]) + self.class_code = 0 + return Class(id(c["@name"]), code, children) + + def do_doc(self, doc): + text = reduce(lambda x, y: x + y, self.list(doc.children)) + return Doc(doc["@type"], doc["@title"], text) + + def do_xref(self, x): + return x["@ref"] + + def do_role(self, r): + return Role(id(r["@name"]), self.children(r)) + + def do_control(self, c): + return Control(id(c["@name"]), self.code(c), self.children(c)) + + def do_rule(self, r): + return Rule(id(r["@name"]), self.children(r)) + + def do_implement(self, i): + return Implement(id(i["@handle"])) + + def do_response(self, r): + return Response(id(r["@name"]), self.children(r)) + + def do_field(self, f): + return Field(id(f["@name"]), id(f["@type"]), self.children(f)) + + def do_struct(self, s): + return Struct(id(s["@name"]), self.code(s), num(s["@size"]), + num(s["@pack"]), self.children(s)) + + def do_command(self, c): + return Command(id(c["@name"]), self.code(c), self.children(c)) + + def do_segments(self, s): + return Anonymous(self.children(s)) + + def do_header(self, h): + return Header(self.children(h)) + + def do_entry(self, e): + return Entry(id(e["@type"])) + + def do_body(self, b): + return Body(self.children(b)) + + def do_result(self, r): + type = r["@type"] + if not type: + type = r["struct/@name"] + return Result(id(type), self.list(r.query["#tag", lambda x: x.name != "struct"])) + + def do_exception(self, e): + return Exception(id(e["@name"]), id(e["@error-code"]), self.children(e)) + +import os, cPickle + +def load(xml): + fname = xml + ".pcl" + if os.path.exists(fname): + file = open(fname, "r") + s = cPickle.load(file) + file.close() + else: + doc = mllib.xml_parse(xml) + s = doc["amqp"].dispatch(Loader()) + s.register() + s.resolve() + file = open(fname, "w") + cPickle.dump(s, file) + file.close() + return s |
