Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2e92c6e
only call load_source if path is a file
bdkearns Oct 10, 2014
39a0323
output switch equals cases with spaces around operator
bdkearns Oct 10, 2014
8a75871
test and fix vars defined inside blocks
bdkearns Oct 10, 2014
e1fac15
add gitignore file
bdkearns Oct 10, 2014
1d3c3f9
add mod.include to setup.py
bdkearns Oct 10, 2014
28f039a
add failing test for class variables with no initial value
bdkearns Oct 13, 2014
3f2407d
fix test, class variables with no init value are set to None
bdkearns Oct 14, 2014
af2b2e4
fix synchronized methods to lock per-instance not per-method
bdkearns Oct 14, 2014
39d019a
use functools.wraps for synchronized decorator
bdkearns Oct 14, 2014
7120676
test/fix overloaded synchronized methods
bdkearns Oct 14, 2014
4353f40
ensure overloaded methods are registered as synchronized
bdkearns Oct 14, 2014
2d5e911
print differences when testing
bdkearns Oct 14, 2014
c994f83
some changes for py3 compat
bdkearns Oct 14, 2014
150e5ce
use config.every rather than config.last for configHandlers
bdkearns Oct 15, 2014
0b66998
use config.every rather than config.last for typeSubs
bdkearns Oct 15, 2014
daced34
add abc imports when defining interfaces
bdkearns Oct 15, 2014
04dd59c
handle String.valueOf()
bdkearns Oct 15, 2014
96897b9
convert IOException to IOError, test
bdkearns Oct 15, 2014
3463036
remove Math. prefix, test
bdkearns Oct 15, 2014
0c6ee8e
fix continue in for loops
bdkearns Oct 15, 2014
153da8b
put space in static array creator
bdkearns Oct 15, 2014
a7a3d54
don't put L suffix on literals
bdkearns Oct 16, 2014
408deec
change sync helper to be py26 friendly
bdkearns Oct 23, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.class
*.egg-info
*.pyc
3 changes: 2 additions & 1 deletion java2python/compiler/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def __init__(self, config, name=None, type=None, parent=None):
self.children = []
self.config = config
self.decorators = []
self.overloaded = None
self.factory = Factory(config)
self.modifiers = []
self.name = name
Expand Down Expand Up @@ -172,7 +173,7 @@ def configHandler(self, part, suffix='Handler', default=None):
def configHandlers(self, part, suffix='Handlers'):
""" Returns config handlers for this type of template """
name = '{0}{1}{2}'.format(self.typeName, part, suffix)
return imap(self.toIter, self.config.last(name, ()))
return imap(self.toIter, chain(*self.config.every(name, [])))

def dump(self, fd, level=0):
""" Writes the Python source code for this template to the given file. """
Expand Down
24 changes: 18 additions & 6 deletions java2python/compiler/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,12 @@ def acceptType(self, node, memo):
acceptAt = makeAcceptType('at')
acceptClass = makeAcceptType('klass')
acceptEnum = makeAcceptType('enum')
acceptInterface = makeAcceptType('interface')
_acceptInterface = makeAcceptType('interface')

def acceptInterface(self, node, memo):
module = self.parents(lambda x:x.isModule).next()
module.needsAbstractHelpers = True
return self._acceptInterface(node, memo)


class Module(TypeAcceptor, Base):
Expand Down Expand Up @@ -228,7 +233,10 @@ def acceptVarDeclaration(self, node, memo):
if node.firstChildOfType(tokens.TYPE).firstChildOfType(tokens.ARRAY_DECLARATOR_LIST):
val = assgnExp.pushRight('[]')
else:
val = assgnExp.pushRight('{0}()'.format(identExp.type))
if node.firstChildOfType(tokens.TYPE).firstChild().type != tokens.QUALIFIED_TYPE_IDENT:
val = assgnExp.pushRight('{0}()'.format(identExp.type))
else:
val = assgnExp.pushRight('None')
return self


Expand Down Expand Up @@ -358,7 +366,7 @@ class Interface(Class):
""" Interface -> accepts AST branches for Java interfaces. """


class MethodContent(Base):
class MethodContent(VarAcceptor, Base):
""" MethodContent -> accepts trees for blocks within methods. """

def acceptAssert(self, node, memo):
Expand Down Expand Up @@ -399,6 +407,10 @@ def acceptCatch(self, node, memo):

def acceptContinue(self, node, memo):
""" Accept and process a continue statement. """
parent = node.parents(lambda x: x.type in {tokens.FOR, tokens.FOR_EACH, tokens.DO, tokens.WHILE}).next()
if parent.type == tokens.FOR:
updateStat = self.factory.expr(parent=self)
updateStat.walk(parent.firstChildOfType(tokens.FOR_UPDATE), memo)
contStat = self.factory.statement('continue', fs=FS.lsr, parent=self)
if len(node.children):
warn('Detected unhandled continue statement with label; generated code incorrect.')
Expand Down Expand Up @@ -517,7 +529,7 @@ def acceptSwitch(self, node, memo):
# we have at least one node...
parExpr = self.factory.expr(parent=self)
parExpr.walk(parNode, memo)
eqFs = FS.l + '==' + FS.r
eqFs = FS.l + ' == ' + FS.r
for caseIdx, caseNode in enumerate(caseNodes):
isDefault, isFirst = caseNode.type==tokens.DEFAULT, caseIdx==0

Expand Down Expand Up @@ -613,7 +625,7 @@ def acceptWhile(self, node, memo):
whileStat.walk(blkNode, memo)


class Method(VarAcceptor, ModifiersAcceptor, MethodContent):
class Method(ModifiersAcceptor, MethodContent):
""" Method -> accepts AST branches for method-level objects. """

def acceptFormalParamStdDecl(self, node, memo):
Expand Down Expand Up @@ -835,7 +847,7 @@ def acceptThisConstructorCall(self, node, memo):

def acceptStaticArrayCreator(self, node, memo):
""" Accept and process a static array expression. """
self.right = self.factory.expr(fs='[None]*{left}')
self.right = self.factory.expr(fs='[None] * {left}')
self.right.left = self.factory.expr()
self.right.left.walk(node.firstChildOfType(tokens.EXPR), memo)

Expand Down
2 changes: 1 addition & 1 deletion java2python/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def last(self, key, default=None):
@staticmethod
def load(name):
""" Imports and returns a module from dotted form or filename. """
if path.exists(name):
if path.exists(name) and path.isfile(name):
mod = load_source(str(hash(name)), name)
else:
mod = reduce(getattr, name.split('.')[1:], __import__(name))
Expand Down
16 changes: 11 additions & 5 deletions java2python/config/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
modulePrologueHandlers = [
basic.shebangLine,
basic.simpleDocString,
'from __future__ import print_function',
basic.maybeBsr,
basic.maybeAbstractHelpers,
basic.maybeSyncHelpers,
]

Expand Down Expand Up @@ -97,9 +99,9 @@
methodPrologueHandlers = [
basic.maybeAbstractMethod,
basic.maybeClassMethod,
basic.overloadedClassMethods,
# NB: synchronized should come after classmethod
basic.maybeSynchronizedMethod,
basic.overloadedClassMethods,
]


Expand Down Expand Up @@ -131,7 +133,7 @@

# This handler is turns java imports into python imports. No mapping
# of packages is performed:
moduleImportDeclarationHandler = basic.simpleImports
# moduleImportDeclarationHandler = basic.simpleImports

# This import decl. handler can be used instead to produce comments
# instead of import statements:
Expand All @@ -148,6 +150,7 @@
(Type('TRUE'), transform.true2True),
(Type('IDENT'), transform.keywordSafeIdent),

(Type('DECIMAL_LITERAL'), transform.syntaxSafeDecimalLiteral),
(Type('FLOATING_POINT_LITERAL'), transform.syntaxSafeFloatLiteral),

(Type('TYPE') > Type('BOOLEAN'), transform.typeSub),
Expand Down Expand Up @@ -193,8 +196,8 @@

# module output subs.
moduleOutputSubs = [
(r'System\.out\.println\((.*)\)', r'print \1'),
(r'System\.out\.print_\((.*?)\)', r'print \1,'),
(r'System\.out\.println\((.*)\)', r'print(\1)'),
(r'System\.out\.print_\((.*?)\)', r'print(\1, end="")'),
(r'(.*?)\.equals\((.*?)\)', r'\1 == \2'),
(r'(.*?)\.equalsIgnoreCase\((.*?)\)', r'\1.lower() == \2.lower()'),
(r'([\w.]+)\.size\(\)', r'len(\1)'),
Expand All @@ -207,8 +210,9 @@
(r'\.getClass\(\)', '.__class__'),
(r'\.getName\(\)', '.__name__'),
(r'\.getInterfaces\(\)', '.__bases__'),
#(r'String\.valueOf\((.*?)\)', r'str(\1)'),
(r'String\.valueOf\((.*?)\)', r'str(\1)'),
#(r'(\s)(\S*?)(\.toString\(\))', r'\1str(\2)'),
(r'Math\.', ''),
]


Expand Down Expand Up @@ -241,5 +245,7 @@
'java.lang.String' : 'str',

'Object' : 'object',

'IndexOutOfBoundsException' : 'IndexError',
'IOException': 'IOError',
}
13 changes: 9 additions & 4 deletions java2python/mod/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def simpleDocString(obj):


def commentedImports(module, expr):
module.factory.comment(parent=module, left=expr, fs='import: {left}')
module.factory.comment(parent=module, left=expr, fs='#import {left}')


def simpleImports(module, expr):
Expand Down Expand Up @@ -109,11 +109,13 @@ def overloadedClassMethods(method):
cls = method.parent
methods = [o for o in cls.children if o.isMethod and o.name==method.name]
if len(methods) == 1:
if methods[0].overloaded:
yield methods[0].overloaded
return
for i, m in enumerate(methods[1:]):
args = [p['type'] for p in m.parameters]
args = ', '.join(args)
m.decorators.append('@{0}.register({1})'.format(method.name, args))
m.overloaded = '@{0}.register({1})'.format(method.name, args)
m.name = '{0}_{1}'.format(method.name, i)
# for this one only:
yield '@overloaded'
Expand All @@ -131,8 +133,6 @@ def maybeAbstractMethod(method):

def maybeSynchronizedMethod(method):
if 'synchronized' in method.modifiers:
module = method.parents(lambda x:x.isModule).next()
module.needsSyncHelpers = True
yield '@synchronized'


Expand All @@ -158,6 +158,11 @@ def maybeBsr(module):
yield line


def maybeAbstractHelpers(module):
if getattr(module, 'needsAbstractHelpers', False):
yield 'from abc import ABCMeta, abstractmethod'


def maybeSyncHelpers(module):
if getattr(module, 'needsSyncHelpers', False):
for line in getSyncHelpersSrc().split('\n'):
Expand Down
6 changes: 6 additions & 0 deletions java2python/mod/include/classmethod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class classmethod_(classmethod):
""" Classmethod that provides attribute delegation.

"""
def __getattr__(self, name):
return getattr(self.__func__, name)
12 changes: 7 additions & 5 deletions java2python/mod/include/overloading.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@

"""

import new
from types import MethodType as instancemethod

# Make the environment more like Python 3.0
__metaclass__ = type
from itertools import izip as zip
import sys
if sys.version_info[0] < 3:
# Make the environment more like Python 3.0
__metaclass__ = type
from itertools import izip as zip


class overloaded:
Expand All @@ -55,7 +57,7 @@ def __init__(self, default_func):
def __get__(self, obj, type=None):
if obj is None:
return self
return new.instancemethod(self, obj)
return instancemethod(self, obj)

def register(self, *types):
"""Decorator to register an implementation for a specific set of types.
Expand Down
9 changes: 5 additions & 4 deletions java2python/mod/include/sync.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from functools import wraps
from threading import RLock

_locks = {}
def lock_for_object(obj, locks=_locks):
def lock_for_object(obj, locks={}):
return locks.setdefault(id(obj), RLock())


def synchronized(call):
assert call.__code__.co_varnames[0] in ['self', 'cls']
@wraps(call)
def inner(*args, **kwds):
with lock_for_object(call):
with lock_for_object(args[0]):
return call(*args, **kwds)
return inner
17 changes: 12 additions & 5 deletions java2python/mod/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,21 @@ def xform(node, config):
true2True = makeConst('True')


def syntaxSafeDecimalLiteral(node, config):
""" Ensures a Java decimal literal is a valid Python decimal literal. """
value = node.token.text
if value.endswith(('l', 'L')):
value = value[:-1]
node.token.text = value


def syntaxSafeFloatLiteral(node, config):
""" Ensures a Java float literal is a valid Python float literal. """
value = node.token.text
if value.startswith('.'):
value = '0' + value
if value.lower().endswith(('f', 'd')):
value = value[:-1]
elif value.endswith(('l', 'L')):
value = value[:-1] + 'L'
node.token.text = value


Expand Down Expand Up @@ -184,6 +190,7 @@ def typeSub(node, config):
mapping and further discussion.
"""
ident = node.token.text
subs = config.last('typeSubs')
if ident in subs:
node.token.text = subs[ident]
for subs in reversed(config.every('typeSubs', {})):
if ident in subs:
node.token.text = subs[ident]
return
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def doc_files():
'java2python.lang',
'java2python.lib',
'java2python.mod',
'java2python.mod.include',
],

package_data={
Expand Down
20 changes: 20 additions & 0 deletions test/BasicTypes3.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Vector {}

class BasicTypes3 {
Boolean B;
Integer I;
Double D;

String S;
Vector V;

public static void main(String[] args) {
BasicTypes3 bt3 = new BasicTypes3();
System.out.println(bt3.B == null ? 1 : 0);
System.out.println(bt3.I == null ? 1 : 0);
System.out.println(bt3.D == null ? 1 : 0);
System.out.println(bt3.S == null ? 1 : 0);
System.out.println(bt3.V == null ? 1 : 0);
}

}
10 changes: 5 additions & 5 deletions test/Continue0.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ public static void main(String[] args) {
int x = 0;
while (x < 10) {
System.out.println(x);
if (x==6) {
break ;
if (x == 6) {
break;
} else {
x+=2;
continue ;
x += 2;
continue;
}
}
}
}
}
13 changes: 13 additions & 0 deletions test/Continue1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Continue1 {
public static void main(String[] args) {
int[] ints = {1, 2, 3, 4, 5, 6, 7};
for (int x : ints) {
if (x == 6) {
break;
} else if (x == 3) {
continue;
}
System.out.println(x);
}
}
}
14 changes: 14 additions & 0 deletions test/Continue2.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Continue2 {
public static void main(String[] args) {
int x = 0;
do {
System.out.println(x);
if (x == 6) {
break;
} else {
x += 2;
continue;
}
} while (x < 10);
}
}
17 changes: 17 additions & 0 deletions test/Exception0.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import java.io.IOException;

class Exception0 {
static void test() throws IOException {
throw new IOException("test");
}

public static void main(String[] args) {
try {
test();
} catch (IOException e) {
System.out.println("catch");
} finally {
System.out.println("done");
}
}
}
Loading