ast.asdl_antlr.py Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython Show documentation
Show all versions of jython Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
#! /usr/bin/env python
"""Generate Java code from an ASDL description."""
# TO DO
# handle fields that have a type but no name
import os, sys, traceback
import asdl
TABSIZE = 4
MAX_COL = 100
def reflow_lines(s, depth):
"""Reflow the line s indented depth tabs.
Return a sequence of lines where no line extends beyond MAX_COL
when properly indented. The first line is properly indented based
exclusively on depth * TABSIZE. All following lines -- these are
the reflowed lines generated by this function -- start at the same
column as the first character beyond the opening { in the first
line.
"""
size = MAX_COL - depth * TABSIZE
if len(s) < size:
return [s]
lines = []
cur = s
padding = ""
while len(cur) > size:
i = cur.rfind(' ', 0, size)
assert i != -1, "Impossible line to reflow: %s" % `s`
lines.append(padding + cur[:i])
if len(lines) == 1:
# find new size based on brace
j = cur.find('{', 0, i)
if j >= 0:
j += 2 # account for the brace and the space after it
size -= j
padding = " " * j
cur = cur[i+1:]
else:
lines.append(padding + cur)
return lines
class EmitVisitor(asdl.VisitorBase):
"""Visit that emits lines"""
def __init__(self, dir):
self.dir = dir
super(EmitVisitor, self).__init__()
def open(self, package, name, refersToPythonTree=1, useDataOutput=0):
path = os.path.join(self.dir, package, "%s.java" % name)
open(path, "w")
self.file = open(os.path.join(self.dir, package, "%s.java" % name), "w")
print >> self.file, "// Autogenerated AST node"
print >> self.file, 'package org.python.antlr.%s;' % package
if refersToPythonTree:
print >> self.file, 'import org.antlr.runtime.CommonToken;'
print >> self.file, 'import org.antlr.runtime.Token;'
print >> self.file, 'import org.python.antlr.AST;'
print >> self.file, 'import org.python.antlr.PythonTree;'
print >> self.file, 'import org.python.antlr.adapter.AstAdapters;'
print >> self.file, 'import org.python.antlr.base.excepthandler;'
print >> self.file, 'import org.python.antlr.base.expr;'
print >> self.file, 'import org.python.antlr.base.mod;'
print >> self.file, 'import org.python.antlr.base.slice;'
print >> self.file, 'import org.python.antlr.base.stmt;'
print >> self.file, 'import org.python.core.ArgParser;'
print >> self.file, 'import org.python.core.AstList;'
print >> self.file, 'import org.python.core.Py;'
print >> self.file, 'import org.python.core.PyObject;'
print >> self.file, 'import org.python.core.PyString;'
print >> self.file, 'import org.python.core.PyType;'
print >> self.file, 'import org.python.expose.ExposedGet;'
print >> self.file, 'import org.python.expose.ExposedMethod;'
print >> self.file, 'import org.python.expose.ExposedNew;'
print >> self.file, 'import org.python.expose.ExposedSet;'
print >> self.file, 'import org.python.expose.ExposedType;'
if useDataOutput:
print >> self.file, 'import java.io.DataOutputStream;'
print >> self.file, 'import java.io.IOException;'
print >> self.file, 'import java.util.ArrayList;'
print >> self.file
def close(self):
self.file.close()
def emit(self, s, depth):
# XXX reflow long lines?
lines = reflow_lines(s, depth)
for line in lines:
line = (" " * TABSIZE * depth) + line + "\n"
self.file.write(line)
# This step will add a 'simple' boolean attribute to all Sum and Product
# nodes and add a 'typedef' link to each Field node that points to the
# Sum or Product node that defines the field.
class AnalyzeVisitor(EmitVisitor):
index = 0
def makeIndex(self):
self.index += 1
return self.index
def visitModule(self, mod):
self.types = {}
for dfn in mod.dfns:
self.types[str(dfn.name)] = dfn.value
for dfn in mod.dfns:
self.visit(dfn)
def visitType(self, type, depth=0):
self.visit(type.value, type.name, depth)
def visitSum(self, sum, name, depth):
sum.simple = 1
for t in sum.types:
if t.fields:
sum.simple = 0
break
for t in sum.types:
if not sum.simple:
t.index = self.makeIndex()
self.visit(t, name, depth)
def visitProduct(self, product, name, depth):
product.simple = 0
product.index = self.makeIndex()
for f in product.fields:
self.visit(f, depth + 1)
def visitConstructor(self, cons, name, depth):
for f in cons.fields:
self.visit(f, depth + 1)
def visitField(self, field, depth):
field.typedef = self.types.get(str(field.type))
# The code generator itself.
#
class JavaVisitor(EmitVisitor):
def visitModule(self, mod):
for dfn in mod.dfns:
self.visit(dfn)
def visitType(self, type, depth=0):
self.visit(type.value, type.name, depth)
def visitSum(self, sum, name, depth):
if sum.simple and not name == "excepthandler":
self.simple_sum(sum, name, depth)
self.simple_sum_wrappers(sum, name, depth)
else:
self.sum_with_constructor(sum, name, depth)
def simple_sum(self, sum, name, depth):
self.open("ast", "%sType" % name, refersToPythonTree=0)
self.emit('import org.python.antlr.AST;', depth)
self.emit('', 0)
self.emit("public enum %(name)sType {" % locals(), depth)
self.emit("UNDEFINED,", depth + 1)
for i in range(len(sum.types) - 1):
type = sum.types[i]
self.emit("%s," % type.name, depth + 1)
self.emit("%s;" % sum.types[len(sum.types) - 1].name, depth + 1)
self.emit("}", depth)
self.close()
def simple_sum_wrappers(self, sum, name, depth):
for i in range(len(sum.types)):
type = sum.types[i]
self.open("op", type.name, refersToPythonTree=0)
self.emit('import org.python.antlr.AST;', depth)
self.emit('import org.python.antlr.PythonTree;', depth)
self.emit('import org.python.core.Py;', depth)
self.emit('import org.python.core.PyObject;', depth)
self.emit('import org.python.core.PyString;', depth)
self.emit('import org.python.core.PyType;', depth)
self.emit('import org.python.expose.ExposedGet;', depth)
self.emit('import org.python.expose.ExposedMethod;', depth)
self.emit('import org.python.expose.ExposedNew;', depth)
self.emit('import org.python.expose.ExposedSet;', depth)
self.emit('import org.python.expose.ExposedType;', depth)
self.emit('', 0)
self.emit('@ExposedType(name = "_ast.%s", base = AST.class)' % type.name, depth)
self.emit("public class %s extends PythonTree {" % type.name, depth)
self.emit('public static final PyType TYPE = PyType.fromClass(%s.class);' % type.name, depth + 1)
self.emit('', 0)
self.emit("public %s() {" % (type.name), depth)
self.emit("}", depth)
self.emit('', 0)
self.emit("public %s(PyType subType) {" % (type.name), depth)
self.emit("super(subType);", depth + 1)
self.emit("}", depth)
self.emit('', 0)
self.emit("@ExposedNew", depth)
self.emit("@ExposedMethod", depth)
self.emit("public void %s___init__(PyObject[] args, String[] keywords) {}" % type.name, depth)
self.emit('', 0)
self.attributes(type, name, depth);
self.emit('@ExposedMethod', depth + 1)
self.emit('public PyObject __int__() {', depth + 1)
self.emit("return %s___int__();" % type.name, depth + 2)
self.emit("}", depth + 1)
self.emit('', 0)
self.emit("final PyObject %s___int__() {" % type.name, depth + 1)
self.emit('return Py.newInteger(%s);' % str(i + 1), depth + 2)
self.emit("}", depth + 1)
self.emit('', 0)
self.emit("}", depth)
self.close()
def attributes(self, obj, name, depth):
field_list = []
if hasattr(obj, "fields"):
for f in obj.fields:
field_list.append('new PyString("%s")' % f.name)
if len(field_list) > 0:
self.emit("private final static PyString[] fields =", depth + 1)
self.emit("new PyString[] {%s};" % ", ".join(field_list), depth+1)
self.emit('@ExposedGet(name = "_fields")', depth + 1)
self.emit("public PyString[] get_fields() { return fields; }", depth+1)
self.emit("", 0)
else:
self.emit("private final static PyString[] fields = new PyString[0];", depth+1)
self.emit('@ExposedGet(name = "_fields")', depth + 1)
self.emit("public PyString[] get_fields() { return fields; }", depth+1)
self.emit("", 0)
if str(name) in ('stmt', 'expr', 'excepthandler'):
att_list = ['new PyString("lineno")', 'new PyString("col_offset")']
self.emit("private final static PyString[] attributes =", depth + 1)
self.emit("new PyString[] {%s};" % ", ".join(att_list), depth + 1)
self.emit('@ExposedGet(name = "_attributes")', depth + 1)
self.emit("public PyString[] get_attributes() { return attributes; }", depth + 1)
self.emit("", 0)
else:
self.emit("private final static PyString[] attributes = new PyString[0];", depth+1)
self.emit('@ExposedGet(name = "_attributes")', depth + 1)
self.emit("public PyString[] get_attributes() { return attributes; }", depth+1)
self.emit("", 0)
def sum_with_constructor(self, sum, name, depth):
self.open("base", "%s" % name)
self.emit('@ExposedType(name = "_ast.%s", base = AST.class)' % name, depth)
self.emit("public abstract class %(name)s extends PythonTree {" %
locals(), depth)
self.emit("", 0)
self.emit("public static final PyType TYPE = PyType.fromClass(%s.class);" % name, depth + 1);
self.attributes(sum, name, depth);
self.emit("public %(name)s() {" % locals(), depth+1)
self.emit("}", depth+1)
self.emit("", 0)
self.emit("public %(name)s(PyType subType) {" % locals(), depth+1)
self.emit("}", depth+1)
self.emit("", 0)
self.emit("public %(name)s(int ttype, Token token) {" % locals(), depth+1)
self.emit("super(ttype, token);", depth+2)
self.emit("}", depth+1)
self.emit("", 0)
self.emit("public %(name)s(Token token) {" % locals(), depth+1)
self.emit("super(token);", depth+2)
self.emit("}", depth+1)
self.emit("", 0)
self.emit("public %(name)s(PythonTree node) {" % locals(), depth+1)
self.emit("super(node);", depth+2)
self.emit("}", depth+1)
self.emit("", 0)
self.emit("}", depth)
self.close()
for t in sum.types:
self.visit(t, name, depth)
def visitProduct(self, product, name, depth):
self.open("ast", "%s" % name, useDataOutput=1)
self.emit('@ExposedType(name = "_ast.%s", base = AST.class)' % name, depth)
self.emit("public class %(name)s extends PythonTree {" % locals(), depth)
self.emit("public static final PyType TYPE = PyType.fromClass(%s.class);" % name, depth + 1);
for f in product.fields:
self.visit(f, depth + 1)
self.emit("", depth)
self.attributes(product, name, depth)
self.javaMethods(product, name, name, True, product.fields,
depth+1)
self.emit("}", depth)
self.close()
def visitConstructor(self, cons, name, depth):
self.open("ast", cons.name, useDataOutput=1)
ifaces = []
for f in cons.fields:
if str(f.type) == "expr_context":
ifaces.append("Context")
if ifaces:
s = "implements %s " % ", ".join(ifaces)
else:
s = ""
self.emit('@ExposedType(name = "_ast.%s", base = AST.class)' % cons.name, depth);
self.emit("public class %s extends %s %s{" %
(cons.name, name, s), depth)
self.emit("public static final PyType TYPE = PyType.fromClass(%s.class);" % cons.name, depth);
for f in cons.fields:
self.visit(f, depth + 1)
self.emit("", depth)
self.attributes(cons, name, depth)
self.javaMethods(cons, name, cons.name, False, cons.fields, depth+1)
if "Context" in ifaces:
self.emit("public void setContext(expr_contextType c) {", depth + 1)
self.emit('this.ctx = c;', depth + 2)
self.emit("}", depth + 1)
self.emit("", 0)
if str(name) in ('stmt', 'expr', 'excepthandler'):
# The lineno property
self.emit("private int lineno = -1;", depth + 1)
self.emit('@ExposedGet(name = "lineno")', depth + 1)
self.emit("public int getLineno() {", depth + 1)
self.emit("if (lineno != -1) {", depth + 2);
self.emit("return lineno;", depth + 3);
self.emit("}", depth + 2)
self.emit('return getLine();', depth + 2)
self.emit("}", depth + 1)
self.emit("", 0)
self.emit('@ExposedSet(name = "lineno")', depth + 1)
self.emit("public void setLineno(int num) {", depth + 1)
self.emit("lineno = num;", depth + 2);
self.emit("}", depth + 1)
self.emit("", 0)
# The col_offset property
self.emit("private int col_offset = -1;", depth + 1)
self.emit('@ExposedGet(name = "col_offset")', depth + 1)
self.emit("public int getCol_offset() {", depth + 1)
self.emit("if (col_offset != -1) {", depth + 2);
self.emit("return col_offset;", depth + 3);
self.emit("}", depth + 2)
self.emit('return getCharPositionInLine();', depth + 2)
self.emit("}", depth + 1)
self.emit("", 0)
self.emit('@ExposedSet(name = "col_offset")', depth + 1)
self.emit("public void setCol_offset(int num) {", depth + 1)
self.emit("col_offset = num;", depth + 2);
self.emit("}", depth + 1)
self.emit("", 0)
self.emit("}", depth)
self.close()
def javaConstructorHelper(self, fields, depth):
for f in fields:
#if f.seq:
# self.emit("this.%s = new %s(%s);" % (f.name,
# self.javaType(f), f.name), depth+1)
#else:
self.emit("this.%s = %s;" % (f.name, f.name), depth+1)
fparg = self.fieldDef(f)
not_simple = True
if f.typedef is not None and f.typedef.simple:
not_simple = False
#For now ignoring String -- will want to revisit
if not_simple and fparg.find("String") == -1:
if f.seq:
self.emit("if (%s == null) {" % f.name, depth+1);
self.emit("this.%s = new ArrayList<%s>();" % (f.name, self.javaType(f, False)), depth+2)
self.emit("}", depth+1)
self.emit("for(PythonTree t : this.%(name)s) {" % {"name":f.name}, depth+1)
self.emit("addChild(t);", depth+2)
self.emit("}", depth+1)
elif str(f.type) == "expr":
self.emit("addChild(%s);" % (f.name), depth+1)
#XXX: this method used to emit a pickle(DataOutputStream ostream) for cPickle support.
# If we want to re-add it, see Jython 2.2's pickle method in its ast nodes.
def javaMethods(self, type, name, clsname, is_product, fields, depth):
self.javaConstructors(type, name, clsname, is_product, fields, depth)
# The toString() method
self.emit('@ExposedGet(name = "repr")', depth)
self.emit("public String toString() {", depth)
self.emit('return "%s";' % clsname, depth+1)
self.emit("}", depth)
self.emit("", 0)
# The toStringTree() method
self.emit("public String toStringTree() {", depth)
self.emit('StringBuffer sb = new StringBuffer("%s(");' % clsname,
depth+1)
for f in fields:
self.emit('sb.append("%s=");' % f.name, depth+1)
self.emit("sb.append(dumpThis(%s));" % f.name, depth+1)
self.emit('sb.append(",");', depth+1)
self.emit('sb.append(")");', depth+1)
self.emit("return sb.toString();", depth+1)
self.emit("}", depth)
self.emit("", 0)
# The accept() method
self.emit("public R accept(VisitorIF visitor) throws Exception {", depth)
if is_product:
self.emit('traverse(visitor);' % clsname, depth+1)
self.emit('return null;' % clsname, depth+1)
else:
self.emit('return visitor.visit%s(this);' % clsname, depth+1)
self.emit("}", depth)
self.emit("", 0)
# The visitChildren() method
self.emit("public void traverse(VisitorIF> visitor) throws Exception {", depth)
for f in fields:
if self.bltinnames.has_key(str(f.type)):
continue
if f.typedef.simple:
continue
if f.seq:
self.emit('if (%s != null) {' % f.name, depth+1)
self.emit('for (PythonTree t : %s) {' % f.name,
depth+2)
self.emit('if (t != null)', depth+3)
self.emit('t.accept(visitor);', depth+4)
self.emit('}', depth+2)
self.emit('}', depth+1)
else:
self.emit('if (%s != null)' % f.name, depth+1)
self.emit('%s.accept(visitor);' % f.name, depth+2)
self.emit('}', depth)
self.emit("", 0)
def javaConstructors(self, type, name, clsname, is_product, fields, depth):
self.emit("public %s(PyType subType) {" % (clsname), depth)
self.emit("super(subType);", depth + 1)
self.emit("}", depth)
if len(fields) > 0:
self.emit("public %s() {" % (clsname), depth)
self.emit("this(TYPE);", depth + 1)
self.emit("}", depth)
fnames = ['"%s"' % f.name for f in fields]
else:
fnames = []
if str(name) in ('stmt', 'expr', 'excepthandler'):
fnames.extend(['"lineno"', '"col_offset"'])
fpargs = ", ".join(fnames)
self.emit("@ExposedNew", depth)
self.emit("@ExposedMethod", depth)
self.emit("public void %s___init__(PyObject[] args, String[] keywords) {" % clsname, depth)
self.emit('ArgParser ap = new ArgParser("%s", args, keywords, new String[]' % clsname, depth + 1)
self.emit('{%s}, %s, true);' % (fpargs, len(fields)), depth + 2)
i = 0
for f in fields:
self.emit("set%s(ap.getPyObject(%s, Py.None));" % (self.processFieldName(f.name),
str(i)), depth+1)
i += 1
if str(name) in ('stmt', 'expr', 'excepthandler'):
self.emit("int lin = ap.getInt(%s, -1);" % str(i), depth + 1)
self.emit("if (lin != -1) {", depth + 1)
self.emit("setLineno(lin);", depth + 2)
self.emit("}", depth + 1)
self.emit("", 0)
self.emit("int col = ap.getInt(%s, -1);" % str(i+1), depth + 1)
self.emit("if (col != -1) {", depth + 1)
self.emit("setLineno(col);", depth + 2)
self.emit("}", depth + 1)
self.emit("", 0)
self.emit("}", depth)
self.emit("", 0)
fpargs = ", ".join(["PyObject %s" % f.name for f in fields])
self.emit("public %s(%s) {" % (clsname, fpargs), depth)
for f in fields:
self.emit("set%s(%s);" % (self.processFieldName(f.name), f.name), depth+1)
self.emit("}", depth)
self.emit("", 0)
token = asdl.Field('Token', 'token')
token.typedef = False
fpargs = ", ".join([self.fieldDef(f) for f in [token] + fields])
self.emit("public %s(%s) {" % (clsname, fpargs), depth)
self.emit("super(token);", depth+1)
self.javaConstructorHelper(fields, depth)
self.emit("}", depth)
self.emit("", 0)
ttype = asdl.Field('int', 'ttype')
ttype.typedef = False
fpargs = ", ".join([self.fieldDef(f) for f in [ttype, token] + fields])
self.emit("public %s(%s) {" % (clsname, fpargs), depth)
self.emit("super(ttype, token);", depth+1)
self.javaConstructorHelper(fields, depth)
self.emit("}", depth)
self.emit("", 0)
tree = asdl.Field('PythonTree', 'tree')
tree.typedef = False
fpargs = ", ".join([self.fieldDef(f) for f in [tree] + fields])
self.emit("public %s(%s) {" % (clsname, fpargs), depth)
self.emit("super(tree);", depth+1)
self.javaConstructorHelper(fields, depth)
self.emit("}", depth)
self.emit("", 0)
#This is mainly a kludge to turn get/setType -> get/setExceptType because
#getType conflicts with a method on PyObject.
def processFieldName(self, name):
name = str(name).capitalize()
if name == "Type":
name = "ExceptType"
return name
def visitField(self, field, depth):
self.emit("private %s;" % self.fieldDef(field), depth)
self.emit("public %s getInternal%s() {" % (self.javaType(field),
str(field.name).capitalize()), depth)
self.emit("return %s;" % field.name, depth+1)
self.emit("}", depth)
self.emit('@ExposedGet(name = "%s")' % field.name, depth)
self.emit("public PyObject get%s() {" % self.processFieldName(field.name), depth)
if field.seq:
self.emit("return new AstList(%s, AstAdapters.%sAdapter);" % (field.name, field.type), depth+1)
else:
if str(field.type) == 'identifier':
self.emit("if (%s == null) return Py.None;" % field.name, depth+1)
self.emit("return new PyString(%s);" % field.name, depth+1)
elif str(field.type) == 'string' or str(field.type) == 'object':
self.emit("return (PyObject)%s;" % field.name, depth+1)
elif str(field.type) == 'bool':
self.emit("if (%s) return Py.True;" % field.name, depth+1)
self.emit("return Py.False;" % field.name, depth+1)
elif str(field.type) == 'int':
self.emit("return Py.newInteger(%s);" % field.name, depth+1)
elif field.typedef.simple:
self.emit("return AstAdapters.%s2py(%s);" % (str(field.type), field.name), depth+1)
else:
self.emit("return %s;" % field.name, depth+1)
#self.emit("return Py.None;", depth+1)
self.emit("}", depth)
self.emit('@ExposedSet(name = "%s")' % field.name, depth)
self.emit("public void set%s(PyObject %s) {" % (self.processFieldName(field.name), field.name), depth)
if field.seq:
#self.emit("this.%s = new %s(" % (field.name, self.javaType(field)), depth+1)
self.emit("this.%s = AstAdapters.py2%sList(%s);" % (field.name, str(field.type), field.name), depth+1)
else:
self.emit("this.%s = AstAdapters.py2%s(%s);" % (field.name, str(field.type), field.name), depth+1)
self.emit("}", depth)
self.emit("", 0)
bltinnames = {
'int' : 'Integer',
'bool' : 'Boolean',
'identifier' : 'String',
'string' : 'Object',
'object' : 'Object', # was PyObject
#Below are for enums
'boolop' : 'boolopType',
'cmpop' : 'cmpopType',
'expr_context' : 'expr_contextType',
'operator' : 'operatorType',
'unaryop' : 'unaryopType',
}
def fieldDef(self, field):
jtype = self.javaType(field)
name = field.name
return "%s %s" % (jtype, name)
def javaType(self, field, check_seq=True):
jtype = str(field.type)
jtype = self.bltinnames.get(jtype, jtype)
if check_seq and field.seq:
return "java.util.List<%s>" % jtype
return jtype
class VisitorVisitor(EmitVisitor):
def __init__(self, dir):
EmitVisitor.__init__(self, dir)
self.ctors = []
def visitModule(self, mod):
for dfn in mod.dfns:
self.visit(dfn)
self.open("ast", "VisitorIF", refersToPythonTree=0)
self.emit('public interface VisitorIF {', 0)
for ctor in self.ctors:
self.emit("public R visit%s(%s node) throws Exception;" %
(ctor, ctor), 1)
self.emit('}', 0)
self.close()
self.open("ast", "VisitorBase")
self.emit('public abstract class VisitorBase implements VisitorIF {', 0)
for ctor in self.ctors:
self.emit("public R visit%s(%s node) throws Exception {" %
(ctor, ctor), 1)
self.emit("R ret = unhandled_node(node);", 2)
self.emit("traverse(node);", 2)
self.emit("return ret;", 2)
self.emit('}', 1)
self.emit('', 0)
self.emit("abstract protected R unhandled_node(PythonTree node) throws Exception;", 1)
self.emit("abstract public void traverse(PythonTree node) throws Exception;", 1)
self.emit('}', 0)
self.close()
def visitType(self, type, depth=1):
self.visit(type.value, type.name, depth)
def visitSum(self, sum, name, depth):
if not sum.simple:
for t in sum.types:
self.visit(t, name, depth)
def visitProduct(self, product, name, depth):
pass
def visitConstructor(self, cons, name, depth):
self.ctors.append(cons.name)
class ChainOfVisitors:
def __init__(self, *visitors):
self.visitors = visitors
def visit(self, object):
for v in self.visitors:
v.visit(object)
def main(outdir, grammar="Python.asdl"):
mod = asdl.parse(grammar)
if not asdl.check(mod):
sys.exit(1)
c = ChainOfVisitors(AnalyzeVisitor(outdir),
JavaVisitor(outdir),
VisitorVisitor(outdir))
c.visit(mod)
if __name__ == "__main__":
import sys
import getopt
usage = "Usage: python %s [-o outdir] [grammar]" % sys.argv[0]
OUT_DIR = '../src/org/python/antlr/'
try:
opts, args = getopt.getopt(sys.argv[1:], 'o:')
except:
print usage
sys.exit(1)
for o, v in opts:
if o == '-o' and v != '':
OUT_DIR = v
if len(opts) > 1 or len(args) > 1:
print usage
sys.exit(1)
if len(args) == 1:
main(OUT_DIR, args[0])
else:
main(OUT_DIR)