blob: 544151bf76db0e5102b9f7fe5cf0922c1804bfb9 [file] [log] [blame]
#!/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()