| #!/usr/bin/env python |
| |
| # |
| # 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 sys, os, xml |
| |
| from qpid.spec import load, pythonize |
| from textwrap import TextWrapper |
| from xml.sax.handler import ContentHandler |
| |
| class Block: |
| |
| def __init__(self, children): |
| self.children = children |
| |
| def emit(self, out): |
| for child in self.children: |
| if not hasattr(child, "emit"): |
| raise ValueError(child) |
| child.emit(out) |
| |
| if not self.children: |
| out.line("pass") |
| |
| class If: |
| |
| def __init__(self, expr, cons, alt = None): |
| self.expr = expr |
| self.cons = cons |
| self.alt = alt |
| |
| def emit(self, out): |
| out.line("if ") |
| self.expr.emit(out) |
| out.write(":") |
| out.level += 1 |
| self.cons.emit(out) |
| out.level -= 1 |
| if self.alt: |
| out.line("else:") |
| out.level += 1 |
| self.alt.emit(out) |
| out.level -= 1 |
| |
| class Stmt: |
| |
| def __init__(self, code): |
| self.code = code |
| |
| def emit(self, out): |
| out.line(self.code) |
| |
| class Expr: |
| |
| def __init__(self, code): |
| self.code = code |
| |
| def emit(self, out): |
| out.write(self.code) |
| |
| class Abort: |
| |
| def __init__(self, expr): |
| self.expr = expr |
| |
| def emit(self, out): |
| out.line("assert False, ") |
| self.expr.emit(out) |
| |
| WRAPPER = TextWrapper() |
| |
| def wrap(text): |
| return WRAPPER.wrap(" ".join(text.split())) |
| |
| class Doc: |
| |
| def __init__(self, text): |
| self.text = text |
| |
| def emit(self, out): |
| out.line('"""') |
| for line in wrap(self.text): |
| out.line(line) |
| out.line('"""') |
| |
| class Frame: |
| |
| def __init__(self, attrs): |
| self.attrs = attrs |
| self.children = [] |
| self.text = None |
| |
| def __getattr__(self, attr): |
| return self.attrs[attr] |
| |
| def isunicode(s): |
| if isinstance(s, str): |
| return False |
| for ch in s: |
| if ord(ch) > 127: |
| return True |
| return False |
| |
| def string_literal(s): |
| if s == None: |
| return None |
| if isunicode(s): |
| return "%r" % s |
| else: |
| return "%r" % str(s) |
| |
| TRUTH = { |
| "1": True, |
| "0": False, |
| "true": True, |
| "false": False |
| } |
| |
| LITERAL = { |
| "shortstr": string_literal, |
| "longstr": string_literal, |
| "bit": lambda s: TRUTH[s.lower()], |
| "longlong": lambda s: "%r" % long(s) |
| } |
| |
| def literal(s, field): |
| return LITERAL[field.type](s) |
| |
| def palexpr(s, field): |
| if s.startswith("$"): |
| return "msg.%s" % s[1:] |
| else: |
| return literal(s, field) |
| |
| class Translator(ContentHandler): |
| |
| def __init__(self, spec): |
| self.spec = spec |
| self.stack = [] |
| self.content = None |
| self.root = Frame(None) |
| self.push(self.root) |
| |
| def emit(self, out): |
| blk = Block(self.root.children) |
| blk.emit(out) |
| out.write("\n") |
| |
| def peek(self): |
| return self.stack[-1] |
| |
| def pop(self): |
| return self.stack.pop() |
| |
| def push(self, frame): |
| self.stack.append(frame) |
| |
| def startElement(self, name, attrs): |
| self.push(Frame(attrs)) |
| |
| def endElement(self, name): |
| frame = self.pop() |
| if hasattr(self, name): |
| child = getattr(self, name)(frame) |
| else: |
| child = self.handle(name, frame) |
| |
| if child: |
| self.peek().children.append(child) |
| |
| def characters(self, text): |
| frame = self.peek() |
| if frame.text: |
| frame.text += text |
| else: |
| frame.text = text |
| |
| def handle(self, name, frame): |
| for klass in self.spec.classes: |
| pyklass = pythonize(klass.name) |
| if name.startswith(pyklass): |
| name = name[len(pyklass) + 1:] |
| break |
| else: |
| raise ValueError("unknown class: %s" % name) |
| |
| for method in klass.methods: |
| pymethod = pythonize(method.name) |
| if name == pymethod: |
| break |
| else: |
| raise ValueError("unknown method: %s" % name) |
| |
| args = ["%s = %s" % (key, palexpr(val, method.fields.bypyname[key])) |
| for key, val in frame.attrs.items()] |
| if method.content and self.content: |
| args.append("content = %r" % string_literal(self.content)) |
| code = "ssn.%s_%s(%s)" % (pyklass, pymethod, ", ".join(args)) |
| if pymethod == "consume": |
| code = "consumer_tag = %s.consumer_tag" % code |
| return Stmt(code) |
| |
| def pal(self, frame): |
| return Block([Doc(frame.text)] + frame.children) |
| |
| def include(self, frame): |
| base, ext = os.path.splitext(frame.filename) |
| return Stmt("from %s import *" % base) |
| |
| def session(self, frame): |
| return Block([Stmt("cli = open()"), Stmt("ssn = cli.channel(0)"), |
| Stmt("ssn.channel_open()")] + frame.children) |
| |
| def empty(self, frame): |
| return If(Expr("msg == None"), Block(frame.children)) |
| |
| def abort(self, frame): |
| return Abort(Expr(string_literal(frame.text))) |
| |
| def wait(self, frame): |
| return Stmt("msg = ssn.queue(consumer_tag).get(timeout=%r)" % |
| (int(frame.timeout)/1000)) |
| |
| def basic_arrived(self, frame): |
| if frame.children: |
| return If(Expr("msg != None"), Block(frame.children)) |
| |
| def basic_content(self, frame): |
| self.content = frame.text |
| |
| class Emitter: |
| |
| def __init__(self, out): |
| self.out = out |
| self.level = 0 |
| |
| def write(self, code): |
| self.out.write(code) |
| |
| def line(self, code): |
| self.write("\n%s%s" % (" "*self.level, code)) |
| |
| def flush(self): |
| self.out.flush() |
| |
| def close(self): |
| self.out.close() |
| |
| |
| for f in sys.argv[2:]: |
| base, ext = os.path.splitext(f) |
| spec = load(sys.argv[1]) |
| t = Translator(spec) |
| xml.sax.parse(f, t) |
| # out = Emitter(open("%s.py" % base)) |
| out = Emitter(sys.stdout) |
| t.emit(out) |
| out.close() |