Skip to content

Commit 5b7f514

Browse files
committed
Merge pull request natural#33 from bdkearns/master
random fixes
2 parents 6e48015 + 408deec commit 5b7f514

27 files changed

+222
-51
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.class
2+
*.egg-info
3+
*.pyc

java2python/compiler/template.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def __init__(self, config, name=None, type=None, parent=None):
119119
self.children = []
120120
self.config = config
121121
self.decorators = []
122+
self.overloaded = None
122123
self.factory = Factory(config)
123124
self.modifiers = []
124125
self.name = name
@@ -172,7 +173,7 @@ def configHandler(self, part, suffix='Handler', default=None):
172173
def configHandlers(self, part, suffix='Handlers'):
173174
""" Returns config handlers for this type of template """
174175
name = '{0}{1}{2}'.format(self.typeName, part, suffix)
175-
return imap(self.toIter, self.config.last(name, ()))
176+
return imap(self.toIter, chain(*self.config.every(name, [])))
176177

177178
def dump(self, fd, level=0):
178179
""" Writes the Python source code for this template to the given file. """

java2python/compiler/visitor.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,12 @@ def acceptType(self, node, memo):
129129
acceptAt = makeAcceptType('at')
130130
acceptClass = makeAcceptType('klass')
131131
acceptEnum = makeAcceptType('enum')
132-
acceptInterface = makeAcceptType('interface')
132+
_acceptInterface = makeAcceptType('interface')
133+
134+
def acceptInterface(self, node, memo):
135+
module = self.parents(lambda x:x.isModule).next()
136+
module.needsAbstractHelpers = True
137+
return self._acceptInterface(node, memo)
133138

134139

135140
class Module(TypeAcceptor, Base):
@@ -228,7 +233,10 @@ def acceptVarDeclaration(self, node, memo):
228233
if node.firstChildOfType(tokens.TYPE).firstChildOfType(tokens.ARRAY_DECLARATOR_LIST):
229234
val = assgnExp.pushRight('[]')
230235
else:
231-
val = assgnExp.pushRight('{0}()'.format(identExp.type))
236+
if node.firstChildOfType(tokens.TYPE).firstChild().type != tokens.QUALIFIED_TYPE_IDENT:
237+
val = assgnExp.pushRight('{0}()'.format(identExp.type))
238+
else:
239+
val = assgnExp.pushRight('None')
232240
return self
233241

234242

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

360368

361-
class MethodContent(Base):
369+
class MethodContent(VarAcceptor, Base):
362370
""" MethodContent -> accepts trees for blocks within methods. """
363371

364372
def acceptAssert(self, node, memo):
@@ -399,6 +407,10 @@ def acceptCatch(self, node, memo):
399407

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

@@ -613,7 +625,7 @@ def acceptWhile(self, node, memo):
613625
whileStat.walk(blkNode, memo)
614626

615627

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

619631
def acceptFormalParamStdDecl(self, node, memo):
@@ -835,7 +847,7 @@ def acceptThisConstructorCall(self, node, memo):
835847

836848
def acceptStaticArrayCreator(self, node, memo):
837849
""" Accept and process a static array expression. """
838-
self.right = self.factory.expr(fs='[None]*{left}')
850+
self.right = self.factory.expr(fs='[None] * {left}')
839851
self.right.left = self.factory.expr()
840852
self.right.left.walk(node.firstChildOfType(tokens.EXPR), memo)
841853

java2python/config/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def last(self, key, default=None):
2727
@staticmethod
2828
def load(name):
2929
""" Imports and returns a module from dotted form or filename. """
30-
if path.exists(name):
30+
if path.exists(name) and path.isfile(name):
3131
mod = load_source(str(hash(name)), name)
3232
else:
3333
mod = reduce(getattr, name.split('.')[1:], __import__(name))

java2python/config/default.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
modulePrologueHandlers = [
2525
basic.shebangLine,
2626
basic.simpleDocString,
27+
'from __future__ import print_function',
2728
basic.maybeBsr,
29+
basic.maybeAbstractHelpers,
2830
basic.maybeSyncHelpers,
2931
]
3032

@@ -97,9 +99,9 @@
9799
methodPrologueHandlers = [
98100
basic.maybeAbstractMethod,
99101
basic.maybeClassMethod,
102+
basic.overloadedClassMethods,
100103
# NB: synchronized should come after classmethod
101104
basic.maybeSynchronizedMethod,
102-
basic.overloadedClassMethods,
103105
]
104106

105107

@@ -131,7 +133,7 @@
131133

132134
# This handler is turns java imports into python imports. No mapping
133135
# of packages is performed:
134-
moduleImportDeclarationHandler = basic.simpleImports
136+
# moduleImportDeclarationHandler = basic.simpleImports
135137

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

153+
(Type('DECIMAL_LITERAL'), transform.syntaxSafeDecimalLiteral),
151154
(Type('FLOATING_POINT_LITERAL'), transform.syntaxSafeFloatLiteral),
152155

153156
(Type('TYPE') > Type('BOOLEAN'), transform.typeSub),
@@ -193,8 +196,8 @@
193196

194197
# module output subs.
195198
moduleOutputSubs = [
196-
(r'System\.out\.println\((.*)\)', r'print \1'),
197-
(r'System\.out\.print_\((.*?)\)', r'print \1,'),
199+
(r'System\.out\.println\((.*)\)', r'print(\1)'),
200+
(r'System\.out\.print_\((.*?)\)', r'print(\1, end="")'),
198201
(r'(.*?)\.equals\((.*?)\)', r'\1 == \2'),
199202
(r'(.*?)\.equalsIgnoreCase\((.*?)\)', r'\1.lower() == \2.lower()'),
200203
(r'([\w.]+)\.size\(\)', r'len(\1)'),
@@ -207,8 +210,9 @@
207210
(r'\.getClass\(\)', '.__class__'),
208211
(r'\.getName\(\)', '.__name__'),
209212
(r'\.getInterfaces\(\)', '.__bases__'),
210-
#(r'String\.valueOf\((.*?)\)', r'str(\1)'),
213+
(r'String\.valueOf\((.*?)\)', r'str(\1)'),
211214
#(r'(\s)(\S*?)(\.toString\(\))', r'\1str(\2)'),
215+
(r'Math\.', ''),
212216
]
213217

214218

@@ -241,5 +245,7 @@
241245
'java.lang.String' : 'str',
242246

243247
'Object' : 'object',
248+
244249
'IndexOutOfBoundsException' : 'IndexError',
250+
'IOException': 'IOError',
245251
}

java2python/mod/basic.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def simpleDocString(obj):
3636

3737

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

4141

4242
def simpleImports(module, expr):
@@ -109,11 +109,13 @@ def overloadedClassMethods(method):
109109
cls = method.parent
110110
methods = [o for o in cls.children if o.isMethod and o.name==method.name]
111111
if len(methods) == 1:
112+
if methods[0].overloaded:
113+
yield methods[0].overloaded
112114
return
113115
for i, m in enumerate(methods[1:]):
114116
args = [p['type'] for p in m.parameters]
115117
args = ', '.join(args)
116-
m.decorators.append('@{0}.register({1})'.format(method.name, args))
118+
m.overloaded = '@{0}.register({1})'.format(method.name, args)
117119
m.name = '{0}_{1}'.format(method.name, i)
118120
# for this one only:
119121
yield '@overloaded'
@@ -131,8 +133,6 @@ def maybeAbstractMethod(method):
131133

132134
def maybeSynchronizedMethod(method):
133135
if 'synchronized' in method.modifiers:
134-
module = method.parents(lambda x:x.isModule).next()
135-
module.needsSyncHelpers = True
136136
yield '@synchronized'
137137

138138

@@ -158,6 +158,11 @@ def maybeBsr(module):
158158
yield line
159159

160160

161+
def maybeAbstractHelpers(module):
162+
if getattr(module, 'needsAbstractHelpers', False):
163+
yield 'from abc import ABCMeta, abstractmethod'
164+
165+
161166
def maybeSyncHelpers(module):
162167
if getattr(module, 'needsSyncHelpers', False):
163168
for line in getSyncHelpersSrc().split('\n'):
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class classmethod_(classmethod):
2+
""" Classmethod that provides attribute delegation.
3+
4+
"""
5+
def __getattr__(self, name):
6+
return getattr(self.__func__, name)

java2python/mod/include/overloading.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@
3636
3737
"""
3838

39-
import new
39+
from types import MethodType as instancemethod
4040

41-
# Make the environment more like Python 3.0
42-
__metaclass__ = type
43-
from itertools import izip as zip
41+
import sys
42+
if sys.version_info[0] < 3:
43+
# Make the environment more like Python 3.0
44+
__metaclass__ = type
45+
from itertools import izip as zip
4446

4547

4648
class overloaded:
@@ -55,7 +57,7 @@ def __init__(self, default_func):
5557
def __get__(self, obj, type=None):
5658
if obj is None:
5759
return self
58-
return new.instancemethod(self, obj)
60+
return instancemethod(self, obj)
5961

6062
def register(self, *types):
6163
"""Decorator to register an implementation for a specific set of types.

java2python/mod/include/sync.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
from functools import wraps
12
from threading import RLock
23

3-
_locks = {}
4-
def lock_for_object(obj, locks=_locks):
4+
def lock_for_object(obj, locks={}):
55
return locks.setdefault(id(obj), RLock())
66

7-
87
def synchronized(call):
8+
assert call.__code__.co_varnames[0] in ['self', 'cls']
9+
@wraps(call)
910
def inner(*args, **kwds):
10-
with lock_for_object(call):
11+
with lock_for_object(args[0]):
1112
return call(*args, **kwds)
1213
return inner

java2python/mod/transform.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,21 @@ def xform(node, config):
4848
true2True = makeConst('True')
4949

5050

51+
def syntaxSafeDecimalLiteral(node, config):
52+
""" Ensures a Java decimal literal is a valid Python decimal literal. """
53+
value = node.token.text
54+
if value.endswith(('l', 'L')):
55+
value = value[:-1]
56+
node.token.text = value
57+
58+
5159
def syntaxSafeFloatLiteral(node, config):
5260
""" Ensures a Java float literal is a valid Python float literal. """
5361
value = node.token.text
5462
if value.startswith('.'):
5563
value = '0' + value
5664
if value.lower().endswith(('f', 'd')):
5765
value = value[:-1]
58-
elif value.endswith(('l', 'L')):
59-
value = value[:-1] + 'L'
6066
node.token.text = value
6167

6268

@@ -184,6 +190,7 @@ def typeSub(node, config):
184190
mapping and further discussion.
185191
"""
186192
ident = node.token.text
187-
subs = config.last('typeSubs')
188-
if ident in subs:
189-
node.token.text = subs[ident]
193+
for subs in reversed(config.every('typeSubs', {})):
194+
if ident in subs:
195+
node.token.text = subs[ident]
196+
return

0 commit comments

Comments
 (0)