Skip to content

Commit

Permalink
Refs beeware#255 - Initial support for non-builtin exceptions.
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Sep 29, 2016
1 parent 7a7f701 commit 824953c
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 41 deletions.
23 changes: 21 additions & 2 deletions tests/structures/test_exception.py
Expand Up @@ -64,15 +64,34 @@ def test_reraise_named(self):
print('Done.')
""")

@expectedFailure
def test_raise_custom_exception(self):
self.assertCodeExecution("""
class MyException(Exception):
pass
try:
raise MyException("This is the exception")
raise MyException()
except MyException:
print("Got a custom exception")
print('Done.')
""")

@expectedFailure
def test_raise_custom_exception_import_from(self):
self.assertCodeExecution("""
from example import *
try:
raise MyException("This is the exception")
except MyException:
print("Got a custom exception")
print('Done.')
""",
extra_code={
'example':
"""
class MyException(Exception):
pass
"""
})
43 changes: 40 additions & 3 deletions voc/python/ast.py
Expand Up @@ -114,6 +114,36 @@ def visit_Attribute(self, node):
pass


# class DefinedClassVisitor(ast.NodeVisitor):
# def __init__(self, symbols, namespace):
# self.symbols = symbols
# self.names =
# self.namespace = namespace

# parts = namespace.split('.')

# self.locals = self.symbols[parts[0]]
# for part in parts[1:]
# self.locals = self.locals.setdefault(part, {})

# def visit_Import(self, node):
# print(dump(node))
# pass

# def visit_ImportFrom(self, node):
# print(dump(node))
# pass

# def visit_ClassDef(self, node):
# print(dump(node))
# self.locals
# pass

# def visit_Assign(self, node):
# print(dump(node))
# pass


class Visitor(ast.NodeVisitor):
def __init__(self, namespace, filename, verbosity=1):
super().__init__()
Expand All @@ -127,6 +157,8 @@ def __init__(self, namespace, filename, verbosity=1):

self.current_exc_name = []

self.symbol_namespace = {}

@property
def context(self):
return self._context[-1]
Expand All @@ -139,6 +171,9 @@ def pop_context(self):
self.context.visitor_teardown()
self._context.pop()

def full_classref(self, name, default_prefix=None):
return self.symbol_namespace.get(name, '.'.join([default_prefix, name])).replace('.', '/')

def visit(self, node):
try:
super().visit(node)
Expand Down Expand Up @@ -342,6 +377,8 @@ def visit_ClassDef(self, node):
self.visit(child)
self.pop_context()

self.symbol_namespace[class_name] = klass.class_name

@node_visitor
def visit_Return(self, node):
# expr? value):
Expand Down Expand Up @@ -511,7 +548,7 @@ def visit_Raise(self, node):
name = node.exc.id
args = []

exception = 'org/python/exceptions/%s' % name
exception = self.full_classref(name, default_prefix='org.python.exceptions')
self.context.add_opcodes(
JavaOpcodes.NEW(exception),
JavaOpcodes.DUP(),
Expand Down Expand Up @@ -1940,11 +1977,11 @@ def visit_ExceptHandler(self, node):
# expr? type, identifier? name, stmt* body):
if isinstance(node.type, ast.Tuple):
exception = [
'org/python/exceptions/%s' % exc.id
self.full_classref(exc.id, default_prefix='org.python.exceptions')
for exc in node.type.elts
]
elif node.type:
exception = 'org/python/exceptions/%s' % node.type.id
exception = self.full_classref(node.type.id, default_prefix='org.python.exceptions')
else:
exception = None

Expand Down
36 changes: 20 additions & 16 deletions voc/python/klass.py
Expand Up @@ -15,7 +15,7 @@


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, verbosity=0, include_default_constructor=False):
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, include_default_constructor=True):
super().__init__(parent=module, verbosity=verbosity)
self.name = name
if namespace is None:
Expand All @@ -24,7 +24,7 @@ def __init__(self, module, name, namespace=None, bases=None, extends=None, imple
self.namespace = namespace

self.bases = bases if bases else []
self.extends = extends
self._extends = extends

self.implements = implements if implements else []
self.public = public
Expand Down Expand Up @@ -60,11 +60,6 @@ def module(self):
return self._parent

def visitor_setup(self):
if self.extends:
base_descriptor = self.extends.replace('.', '/')
else:
base_descriptor = 'org/python/types/Object'

self.add_opcodes(
# JavaOpcodes.LDC_W("STATIC BLOCK OF " + self.klass.descriptor),
# JavaOpcodes.INVOKESTATIC('org/Python', 'debug', '(Ljava/lang/String;)V'),
Expand All @@ -81,11 +76,11 @@ def visitor_setup(self):
JavaOpcodes.LDC_W(self.descriptor),
JavaOpcodes.INVOKESTATIC('org/python/types/Type', 'pythonType', '(Ljava/lang/String;)Lorg/python/types/Type;'),

JavaOpcodes.LDC_W(base_descriptor),
JavaOpcodes.LDC_W(self.extends_descriptor),
JavaOpcodes.INVOKESTATIC('org/python/types/Type', 'pythonType', '(Ljava/lang/String;)Lorg/python/types/Type;'),

# JavaOpcodes.DUP(),
# JavaOpcodes.LDC_W("__base__ for %s should be %s; is" % (self.klass, base_descriptor)),
# JavaOpcodes.LDC_W("__base__ for %s should be %s; is" % (self.klass, self.extends_descriptor)),
# JavaOpcodes.SWAP(),
# JavaOpcodes.INVOKESTATIC('org/Python', 'debug', '(Ljava/lang/String;Ljava/lang/Object;)V'),

Expand Down Expand Up @@ -240,10 +235,24 @@ def visitor_teardown(self):
JavaOpcodes.RETURN()
)

@property
def extends(self):
if self._extends:
return self._extends
else:
if 'Exception' in self.bases:
return 'org.python.exceptions.Exception'
else:
return 'org.python.types.Object'

@property
def extends_descriptor(self):
return self.extends.replace('.', '/')

def transpile(self):
classfile = JavaClass(
self.descriptor,
extends=self.extends if self.extends else 'org/python/types/Object',
extends=self.extends_descriptor,
implements=self.implements,
public=self.public,
final=self.final
Expand Down Expand Up @@ -284,11 +293,6 @@ def transpile(self):

# Ensure the class has a class protected, no-args init() so that
# instances can be instantiated.
if self.extends:
base_descriptor = self.extends.replace('.', '/')
else:
base_descriptor = 'org/python/types/Object'

if self.include_default_constructor:
classfile.methods.append(
JavaMethod(
Expand All @@ -302,7 +306,7 @@ def transpile(self):
max_locals=1,
code=[
JavaOpcodes.ALOAD_0(),
JavaOpcodes.INVOKESPECIAL(base_descriptor, '<init>', '()V'),
JavaOpcodes.INVOKESPECIAL(self.extends_descriptor, '<init>', '()V'),
JavaOpcodes.RETURN(),
]
)
Expand Down
28 changes: 8 additions & 20 deletions voc/python/methods.py
Expand Up @@ -347,27 +347,15 @@ def signature(self):
return '([Lorg/python/Object;Ljava/util/Map;)V'

def visitor_setup(self):
if self.klass.extends:
super_class = self.klass.extends
else:
super_class = 'org/python/types/Object'

# Get the __init__ method for the class...
if self.klass.extends:
self.add_opcodes(
# Create the instance
JavaOpcodes.ALOAD_0(),
JavaOpcodes.DUP(),
# TODO - this only allows using the default constructor
# for extended Java classes.
JavaOpcodes.INVOKESPECIAL(super_class, '<init>', '()V'),
)
else:
self.add_opcodes(
JavaOpcodes.ALOAD_0(),
JavaOpcodes.DUP(),
JavaOpcodes.INVOKESPECIAL(super_class, '<init>', '()V'),
)
self.add_opcodes(
# Create the instance
JavaOpcodes.ALOAD_0(),
JavaOpcodes.DUP(),
# TODO - this only allows using the default constructor
# for extended Java classes.
JavaOpcodes.INVOKESPECIAL(self.klass.extends_descriptor, '<init>', '()V'),
)

self.add_opcodes(
JavaOpcodes.INVOKESTATIC('org/python/types/Type', 'toPython', '(Ljava/lang/Object;)Lorg/python/Object;'),
Expand Down

0 comments on commit 824953c

Please sign in to comment.