| # |
| # 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 os, cPickle, datatypes, datetime |
| from codec010 import StringCodec |
| from util import mtime, fill |
| |
| 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.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 register(self, node): |
| Type.register(self, node) |
| if self.code is not None: |
| self.spec.types[self.code] = self |
| |
| 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 Enum: |
| |
| def __init__(self, name): |
| self.name = name |
| self._names = () |
| self._values = () |
| |
| def values(self): |
| return self._values |
| |
| def __repr__(self): |
| return "%s(%s)" % (self.name, ", ".join(self._names)) |
| |
| 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) |
| try: |
| enum = node.spec.enums[node.name] |
| except KeyError: |
| enum = Enum(node.name) |
| node.spec.enums[node.name] = enum |
| setattr(enum, self.name, self.value) |
| enum._names += (self.name,) |
| enum._values += (self.value,) |
| |
| class Composite(Type, Coded): |
| |
| def __init__(self, name, label, code, size, pack, children): |
| Coded.__init__(self, code) |
| Type.__init__(self, name, children) |
| self.label = label |
| self.fields = [] |
| self.size = size |
| self.pack = pack |
| |
| def new(self, args, kwargs): |
| return datatypes.Struct(self, *args, **kwargs) |
| |
| def decode(self, codec): |
| codec.read_size(self.size) |
| if self.code is not None: |
| code = codec.read_uint16() |
| assert self.code == code |
| return datatypes.Struct(self, **self.decode_fields(codec)) |
| |
| def decode_fields(self, codec): |
| flags = 0 |
| for i in range(self.pack): |
| flags |= (codec.read_uint8() << 8*i) |
| |
| result = {} |
| |
| 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 result |
| |
| def encode(self, codec, value): |
| sc = StringCodec(self.spec) |
| if self.code is not None: |
| sc.write_uint16(self.code) |
| self.encode_fields(sc, value) |
| codec.write_size(self.size, len(sc.encoded)) |
| codec.write(sc.encoded) |
| |
| def encode_fields(self, codec, values): |
| flags = 0 |
| for i in range(len(self.fields)): |
| f = self.fields[i] |
| if f.type.is_present(values[f.name]): |
| 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]) |
| |
| def docstring(self): |
| docs = [] |
| if self.label: |
| docs.append(self.label) |
| docs += [d.text for d in self.docs] |
| s = "\n\n".join([fill(t, 2) for t in docs]) |
| for f in self.fields: |
| fdocs = [] |
| if f.label: |
| fdocs.append(f.label) |
| else: |
| fdocs.append("") |
| fdocs += [d.text for d in f.docs] |
| s += "\n\n" + "\n\n".join([fill(fdocs[0], 4, f.name)] + |
| [fill(t, 4) for t in fdocs[1:]]) |
| return s |
| |
| |
| class Field(Named, Node, Lookup): |
| |
| def __init__(self, name, label, type, children): |
| Named.__init__(self, name) |
| Node.__init__(self, children) |
| self.label = label |
| self.type = type |
| self.exceptions = [] |
| |
| def default(self): |
| return None |
| |
| 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) |
| if self.code is not None: |
| self.spec.structs[self.code] = self |
| self.spec.structs_by_name[self.name] = self |
| self.pyname = self.name |
| self.pydoc = self.docstring() |
| |
| 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: |
| |
| def __init__(self): |
| self.segment_type = None |
| |
| 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, label, code, children): |
| Composite.__init__(self, name, label, code, 0, 2, children) |
| Segment.__init__(self) |
| 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.pyname = self.qname.replace(".", "_") |
| self.pydoc = self.docstring() |
| self.spec.instructions[self.pyname] = self |
| |
| class Control(Instruction): |
| |
| def __init__(self, name, code, label, children): |
| Instruction.__init__(self, name, code, label, 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, label, code, children): |
| Instruction.__init__(self, name, label, code, children) |
| self.result = None |
| self.exceptions = [] |
| self.segments = [] |
| |
| def register(self, node): |
| Instruction.register(self, node) |
| node.commands.append(self) |
| self.spec.commands[self.code] = self |
| self.segment_type = self.spec["segment_type.command"].value |
| self.track = self.spec["track.command"].value |
| |
| class Header(Segment, Node): |
| |
| def __init__(self, children): |
| Segment.__init__(self) |
| Node.__init__(self, children) |
| self.entries = [] |
| |
| def register(self, node): |
| Segment.register(self, node) |
| self.segment_type = self.spec["segment_type.header"].value |
| Node.register(self) |
| |
| 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, Node): |
| |
| def __init__(self, children): |
| Segment.__init__(self) |
| Node.__init__(self, children) |
| |
| def register(self, node): |
| Segment.register(self, node) |
| self.segment_type = self.spec["segment_type.body"].value |
| Node.register(self) |
| |
| 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.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): |
| |
| ENCODINGS = { |
| basestring: "vbin16", |
| int: "int64", |
| long: "int64", |
| float: "float", |
| None.__class__: "void", |
| list: "list", |
| tuple: "list", |
| dict: "map", |
| datatypes.timestamp: "datetime", |
| datetime.datetime: "datetime" |
| } |
| |
| 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 = {} |
| self.structs_by_name = {} |
| self.enums = {} |
| |
| def encoding(self, klass): |
| if Spec.ENCODINGS.has_key(klass): |
| return self.named[Spec.ENCODINGS[klass]] |
| for base in klass.__bases__: |
| result = self.encoding(base) |
| if result != None: |
| return result |
| |
| 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"]), c["@label"], 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"]), f["@label"], id(f["@type"]), self.children(f)) |
| |
| def do_struct(self, s): |
| return Struct(id(s["@name"]), s["@label"], self.code(s), num(s["@size"]), |
| num(s["@pack"]), self.children(s)) |
| |
| def do_command(self, c): |
| return Command(id(c["@name"]), c["@label"], 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)) |
| |
| def load(xml): |
| fname = xml + ".pcl" |
| |
| if os.path.exists(fname) and mtime(fname) > mtime(__file__): |
| 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() |
| |
| try: |
| file = open(fname, "w") |
| except IOError: |
| file = None |
| |
| if file: |
| cPickle.dump(s, file) |
| file.close() |
| |
| return s |