Skip to content

Commit

Permalink
Did a proper job on the __main__ entrypoint.
Browse files Browse the repository at this point in the history
This adds a verbosity flag, plus proper flags for output directory and prefixing.
  • Loading branch information
freakboy3742 committed Jan 3, 2016
1 parent c1bd25e commit 592a87f
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 60 deletions.
1 change: 0 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,3 @@ want to contribute code, please `fork the code`_ and `submit a pull request`_.
.. _log them on Github: https://github.com/pybee/voc/issues
.. _fork the code: https://github.com/pybee/voc
.. _submit a pull request: https://github.com/pybee/voc/pulls

3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ VOC
===

.. image:: _static/logo.png
:target: https://pybee.org/voc

**VOC is an early alpha project. If it breaks, you get to keep all the shiny pieces.**

Expand All @@ -10,7 +11,7 @@ class file that can then be executed on a JVM, or run through a DEX tool to
run on Android. It does this *at the bytecode level*, rather than the source code level.

It honors Python 3.4 syntax and conventions, but also provides the ability to
reference objects and classes defined in Java code, andimplement interfaces
reference objects and classes defined in Java code, and implement interfaces
defined in Java code.

.. toctree::
Expand Down
10 changes: 6 additions & 4 deletions docs/tutorials/tutorial-0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@ class file:

.. code-block:: bash
$ python -m voc example.py
$ voc -v example.py
This runs the VOC compiler over the `example.py` source file. The `-v` flag
asks VOC to use verbose output so you can see what is going on.
You will see output like the following:

.. code-block:: bash
Creating class 'example'...
Writing example/__init__.class...
Done.
Compiling example.py ...
Adding default main method...
Writing python/example/__init__.class ...
This will produce an ``__init__.class`` in the ``python/example`` namespace.
This classfile can run on any Java 1.7+ VM. To run the project, type:
Expand Down
4 changes: 2 additions & 2 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def runAsPython(test_dir, main_code, extra_code=None, run_in_function=False, arg
def runAsJava(test_dir, main_code, extra_code=None, run_in_function=False, args=None):
"""Run a block of Python code as a Java program."""
# Output source code into test directory
transpiler = Transpiler()
transpiler = Transpiler(verbosity=0)

# Don't redirect stderr; we want to see any errors from the transpiler
# as top level test failures.
Expand All @@ -142,7 +142,7 @@ def runAsJava(test_dir, main_code, extra_code=None, run_in_function=False, args=
for name, code in extra_code.items():
transpiler.transpile_string("%s.py" % name.replace('.', os.path.sep), adjust(code))

transpiler.write(test_dir, verbosity=0)
transpiler.write(test_dir)

if args is None:
args = []
Expand Down
58 changes: 41 additions & 17 deletions voc/__main__.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,49 @@
import sys
from .transpiler import transpile
import argparse


def main():
if len(sys.argv) == 2:
srcdir = '.'
outdir = None
elif len(sys.argv) == 3:
srcdir = sys.argv[2]
outdir = None
elif len(sys.argv) == 4:
srcdir = sys.argv[2]
outdir = sys.argv[3]
else:
print("Usage: voc <path to .py file> [<input prefix>] [<output dir>]")
print()
print(' e.g.: voc tests/example.py src out')
sys.exit(1)
parser = argparse.ArgumentParser(
prog='voc',
description='Transpiles Python code to Java class files.'
)

transpile(sys.argv[1], srcdir=srcdir, outdir=outdir)
parser.add_argument(
'-o', '--output',
help='The directory where class files should be output.',
default='.'
)
parser.add_argument(
'-p', '--prefix',
help='The prefix to strip from all source file paths.',
default='.'
)
parser.add_argument(
'-n', '--namespace',
help='The namespace for the generated Java classfiles.',
default='python'
)
parser.add_argument(
'-v', '--verbosity',
action='count',
default=0
)
parser.add_argument(
'input',
metavar='source file',
nargs='+',
help='The source file or directory to compile'
)

args = parser.parse_args()

if __name__ == "__main__":
transpile(
input=args.input,
prefix=args.prefix,
outdir=args.output,
namespace=args.namespace,
verbosity=args.verbosity
)

if __name__ == '__main__':
main()
25 changes: 24 additions & 1 deletion voc/java/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -745,8 +745,31 @@ class DLOAD(Opcode):
# Stack: → value
code = 0x18

def __init__(self):
def __init__(self, var):
super(DLOAD, self).__init__()
self.var = var

def __len__(self):
return 2

def __arg_repr__(self):
return ' %s' % self.var

@classmethod
def read_extra(cls, reader, dump=None):
var = reader.read_u1()
return cls(var)

def write_extra(self, writer):
writer.write_u1(self.var)

@property
def produce_count(self):
return 1

@property
def consume_count(self):
return 0


class DLOAD_0(Opcode):
Expand Down
13 changes: 7 additions & 6 deletions voc/python/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ class IgnoreBlock(Exception):


class Block:
def __init__(self, parent=None, commands=None):
def __init__(self, parent=None, commands=None, verbosity=0):
self.parent = parent
self.commands = commands if commands else []
self.verbosity = verbosity

self.local_vars = {}
self.deleted_vars = set()

Expand Down Expand Up @@ -52,7 +54,7 @@ def load_name(self, name, use_locals):
def delete_name(self, name, use_locals):
raise NotImplementedError('Abstract class `block` cannot be used directly.')

def extract(self, code, debug=False):
def extract(self, code):
"""Break a code object into the parts it defines, populating the
provided block.
Expand All @@ -70,13 +72,12 @@ def extract(self, code, debug=False):

commands.reverse()

if True:
print ('=====' * 10)
if self.verbosity > 1:
print ('=' * len(str(code)))
print (code)
print ('-----' * 10)
print ('-' * len(str(code)))
for command in commands:
command.dump()
print ('=====' * 10)

# Append the extracted commands to any pre-existing ones.
self.commands.extend(commands)
Expand Down
5 changes: 3 additions & 2 deletions voc/python/klass.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def add_method(self, full_method_name, code, annotations):
'annotation': annotations.get('return', 'org.python.Object').replace('.', '/')
},
static=True,
verbosity=self.klass.verbosity
)
method.extract(code)
self.klass.add_method(method)
Expand Down Expand Up @@ -186,8 +187,8 @@ def transpile_teardown(self):


class Class(Block):
def __init__(self, module, name, namespace=None, bases=None, extends=None, implements=None, public=True, final=False, methods=None, fields=None, init=None):
super().__init__(module)
def __init__(self, module, name, namespace=None, bases=None, extends=None, implements=None, public=True, final=False, methods=None, fields=None, init=None, verbosity=0):
super().__init__(module, verbosity=verbosity)
self.name = name
self.bases = bases if bases else ['org/python/types/Object']
self.extends = extends
Expand Down
20 changes: 13 additions & 7 deletions voc/python/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def descriptor(annotation):


class Method(Block):
def __init__(self, parent, name, parameters, returns=None, static=False, commands=None):
super().__init__(parent, commands=commands)
def __init__(self, parent, name, parameters, returns=None, static=False, commands=None, verbosity=0):
super().__init__(parent, commands=commands, verbosity=verbosity)
self.name = name
self.parameters = parameters

Expand Down Expand Up @@ -181,6 +181,7 @@ def add_method(self, method_name, code, annotations):
implements=['org/python/Callable'],
public=True,
final=True,
verbosity=self.module.verbosity
)

method = ClosureMethod(
Expand All @@ -189,7 +190,8 @@ def add_method(self, method_name, code, annotations):
parameters=extract_parameters(code, annotations),
returns={
'annotation': annotations.get('return', 'org/python/Object').replace('.', '/')
}
},
verbosity=self.module.verbosity
)
method.extract(code)
callable.methods.append(method)
Expand Down Expand Up @@ -237,7 +239,7 @@ def transpile(self):


class InitMethod(Method):
def __init__(self, parent):
def __init__(self, parent, verbosity=0):
super().__init__(
parent, '<init>',
parameters=[
Expand All @@ -258,6 +260,7 @@ def __init__(self, parent):
}
],
returns={'annotation': None},
verbosity=verbosity
)

def __repr__(self):
Expand Down Expand Up @@ -311,13 +314,14 @@ def transpile_teardown(self):


class InstanceMethod(Method):
def __init__(self, parent, name, parameters, returns=None, static=False, commands=None):
def __init__(self, parent, name, parameters, returns=None, static=False, commands=None, verbosity=0):
super().__init__(
parent, name,
parameters=parameters,
returns=returns,
static=static,
commands=commands,
verbosity=verbosity
)

def __repr__(self):
Expand Down Expand Up @@ -749,13 +753,14 @@ def transpile_wrapper(self):


class MainMethod(Method):
def __init__(self, parent, commands=None, end_offset=None):
def __init__(self, parent, commands=None, end_offset=None, verbosity=0):
super().__init__(
parent, '__main__',
parameters=[{'name': 'args', 'annotation': 'argv'}],
returns={'annotation': None},
static=True,
commands=commands,
verbosity=verbosity
)
self.end_offset = end_offset

Expand Down Expand Up @@ -886,14 +891,15 @@ def method_attributes(self):


class ClosureMethod(Method):
def __init__(self, parent, name, parameters, returns=None, static=False, commands=None):
def __init__(self, parent, name, parameters, returns=None, static=False, commands=None, verbosity=0):

super().__init__(
parent, name,
parameters=parameters,
returns=returns,
static=static,
commands=commands,
verbosity=verbosity
)

def __repr__(self):
Expand Down
12 changes: 7 additions & 5 deletions voc/python/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,16 @@ def add_method(self, method_name, code, annotations):
'annotation': annotations.get('return', 'org.python.Object').replace('.', '/')
},
static=True,
verbosity=self.module.verbosity
)
method.extract(code)
self.module.methods.append(method)
return method


class Module(Block):
def __init__(self, namespace, sourcefile):
super().__init__()
def __init__(self, namespace, sourcefile, verbosity=0):
super().__init__(verbosity=verbosity)
self.sourcefile = sourcefile

parts = os.path.splitext(sourcefile)[0].split(os.path.sep)
Expand Down Expand Up @@ -157,7 +158,7 @@ def materialize(self):
# Marker for the end of the main block:
if cmd.is_main_end(main_end):
try:
main = MainMethod(self, main_commands, end_offset=main_end)
main = MainMethod(self, main_commands, end_offset=main_end, verbosity=self.verbosity)
except IgnoreBlock:
pass
main_end = None
Expand Down Expand Up @@ -188,8 +189,9 @@ def materialize(self):
self.body = StaticBlock(self, body_commands)

if main is None:
print("Adding default main method...")
main = MainMethod(self, [])
if self.verbosity:
print("Adding default main method...")
main = MainMethod(self, [], verbosity=self.verbosity)

self.methods.append(main)

Expand Down
9 changes: 8 additions & 1 deletion voc/python/opcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2535,7 +2535,14 @@ def materialize(self, context, arguments):
else:
raise Exception("Unknown meta keyword " + str(key))

self.klass = Class(context.parent, class_name, bases=bases, extends=extends, implements=implements)
self.klass = Class(
context.parent,
class_name,
bases=bases,
extends=extends,
implements=implements,
verbosity=context.parent.verbosity
)
self.klass.extract(code)
context.parent.classes.append(self.klass)

Expand Down
Loading

0 comments on commit 592a87f

Please sign in to comment.