diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..7eebd73
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/java2python.iml b/.idea/java2python.iml
new file mode 100644
index 0000000..abc6379
--- /dev/null
+++ b/.idea/java2python.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..7ba73c2
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..9a770cd
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/j2py.py b/j2py.py
new file mode 100644
index 0000000..6eb1a40
--- /dev/null
+++ b/j2py.py
@@ -0,0 +1,259 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" j2py -> Java to Python compiler script.
+
+This is all very ordinary. We import the package bits, open and read
+a file, translate it, and write it out.
+
+"""
+import sys
+from argparse import ArgumentParser, ArgumentTypeError
+from collections import defaultdict
+from logging import _levelNames as logLevels, exception, warning, info, basicConfig
+from os import path, makedirs
+from time import time
+
+from java2python.compiler import Module, buildAST, transformAST
+from java2python.config import Config
+from java2python.lib import escapes
+
+
+version = '0.5.1'
+
+
+def logLevel(value):
+ """ Returns a valid logging level or raises and exception. """
+ msg = 'invalid loglevel: %r'
+ try:
+ lvl = int(value)
+ except (ValueError, ):
+ name = value.upper()
+ if name not in logLevels:
+ raise ArgumentTypeError(msg % value)
+ lvl = logLevels[name]
+ else:
+ if lvl not in logLevels:
+ raise ArgumentTypeError(msg % value)
+ return lvl
+
+
+def configFromDir(inname, dirname):
+ """ Returns a file name from the given config directory. """
+ name = path.join(dirname, path.basename(path.splitext(inname)[0]))
+ return '%s.py' % path.abspath(name)
+
+
+def runMain(options):
+ """ Runs our main function with profiling if indicated by options. """
+ if options.profile:
+ import cProfile, pstats
+ prof = cProfile.Profile()
+ prof.runcall(runOneOrMany, options)
+ stats = pstats.Stats(prof, stream=sys.stderr)
+ stats.strip_dirs().sort_stats('cumulative')
+ stats.print_stats().print_callers()
+ return 0
+ else:
+ return runOneOrMany(options)
+
+def runOneOrMany(options):
+ """ Runs our main transformer with each of the input files. """
+ infile, outfile = options.inputfile, options.outputfile
+
+ if infile and not isinstance(infile, file) and path.isdir(infile):
+ if outfile and not isinstance(outfile, file) and not path.isdir(outfile):
+ warning('Must specify output directory or stdout when using input directory.')
+ return 2
+ def walker(arg, dirname, files):
+ for name in [name for name in files if name.endswith('.java')]:
+ fullname = path.join(dirname, name)
+ options.inputfile = fullname
+ info('opening %s', fullname)
+ if outfile and outfile != '-' and not isinstance(outfile, file):
+ full = path.abspath(path.join(outfile, fullname))
+ head, tail = path.split(full)
+ tail = path.splitext(tail)[0] + '.py'
+ if not path.exists(head):
+ makedirs(head)
+ options.outputfile = path.join(head, tail)
+ runTransform(options)
+ path.walk(infile, walker, None)
+ return 0
+ else:
+ return runTransform(options)
+
+
+def runTransform(options):
+ """ Compile the indicated java source with the given options. """
+ timed = defaultdict(time)
+ timed['overall']
+
+ filein = fileout = filedefault = '-'
+ if options.inputfile and not isinstance(options.inputfile, file):
+ filein = options.inputfile
+ if options.outputfile and not isinstance(options.outputfile, file):
+ fileout = options.outputfile
+ elif fileout != filedefault:
+ fileout = '%s.py' % (path.splitext(filein)[0])
+
+ configs = options.configs
+ if options.configdirs and not isinstance(filein, file):
+ for configdir in options.configdirs:
+ dirname = configFromDir(filein, configdir)
+ if path.exists(dirname):
+ configs.insert(0, dirname)
+ if options.includedefaults:
+ configs.insert(0, 'java2python.config.default')
+
+ try:
+ if filein != '-':
+ source = open(filein).read()
+ else:
+ source = sys.stdin.read()
+ except (IOError, ), exc:
+ code, msg = exc.args[0:2]
+ print 'IOError: %s.' % (msg, )
+ return code
+
+ timed['comp']
+ try:
+ tree = buildAST(source)
+ except (Exception, ), exc:
+ exception('exception while parsing')
+ return 1
+ timed['comp_finish']
+
+ config = Config(configs)
+ timed['xform']
+ transformAST(tree, config)
+ timed['xform_finish']
+
+ timed['visit']
+ module = Module(config)
+ module.sourceFilename = path.abspath(filein) if filein != '-' else None
+ module.name = path.splitext(path.basename(filein))[0] if filein != '-' else ''
+ module.walk(tree)
+ timed['visit_finish']
+
+ timed['encode']
+ source = unicode(module)
+ timed['encode_finish']
+ timed['overall_finish']
+
+ if options.lexertokens:
+ for idx, tok in enumerate(tree.parser.input.tokens):
+ print >> sys.stderr, '{0} {1}'.format(idx, tok)
+ print >> sys.stderr
+
+ if options.javaast:
+ tree.dump(sys.stderr)
+ print >> sys.stderr
+
+ if options.pytree:
+ module.dumpRepr(sys.stderr)
+ print >> sys.stderr
+
+ if not options.skipsource:
+ if fileout == filedefault:
+ output = sys.stdout
+ else:
+ output = open(fileout, 'w')
+ module.name = path.splitext(filein)[0] if filein != '-' else ''
+ print >> output, source
+
+ if not options.skipcompile:
+ try:
+ compile(source, '', 'exec')
+ except (SyntaxError, ), ex:
+ warning('Generated source has invalid syntax. %s', ex)
+ else:
+ info('Generated source has valid syntax.')
+
+ info('Parse: %.4f seconds', timed['comp_finish'] - timed['comp'])
+ info('Visit: %.4f seconds', timed['visit_finish'] - timed['visit'])
+ info('Transform: %.4f seconds', timed['xform_finish'] - timed['xform'])
+ info('Encode: %.4f seconds', timed['encode_finish'] - timed['encode'])
+ info('Total: %.4f seconds', timed['overall_finish'] - timed['overall'])
+ return 0
+
+
+def isWindows():
+ """ True if running on Windows. """
+ return sys.platform.startswith('win')
+
+
+def configLogging(loglevel):
+ """ Configure the logging package. """
+ fmt = '# %(levelname)s %(funcName)s: %(message)s'
+ basicConfig(level=loglevel, format=fmt)
+
+
+def configColors(nocolor):
+ """ Configure the color escapes. """
+ if isWindows() or nocolor:
+ escapes.clear()
+
+
+def configScript(argv):
+ """ Return an options object from the given argument sequence. """
+ parser = ArgumentParser(
+ description='Translate Java source code to Python.',
+ epilog='Refer to https://github.com/natural/java2python for docs and support.'
+ )
+
+ add = parser.add_argument
+ add(dest='inputfile', nargs='?',
+ help='Read from INPUT. May use - for stdin (default).',
+ metavar='INPUT', default=None)
+ add(dest='outputfile', nargs='?',
+ help='Write to OUTPUT. May use - for stdout (default).',
+ metavar='OUTPUT', default=None)
+ add('-c', '--config', dest='configs',
+ help='Use CONFIG file or module. May be repeated.',
+ metavar='CONFIG', default=[], action='append')
+ add('-d', '--config-dir', dest='configdirs',
+ help='Use DIR to match input filename with config filename.',
+ metavar='DIR', default=[], action='append')
+ add('-f', '--profile', dest='profile',
+ help='Profile execution and print results to stderr.',
+ default=False, action='store_true')
+ add('-j', '--java-ast', dest='javaast',
+ help='Print java source AST tree to stderr.',
+ default=False, action='store_true')
+ add('-k', '--skip-compile', dest='skipcompile',
+ help='Skip compile check on translated source.',
+ default=False, action='store_true')
+ add('-l', '--log-level', dest='loglevel',
+ help='Set log level by name or value.',
+ default='WARN', type=logLevel)
+ add('-n', '--no-defaults', dest='includedefaults',
+ help='Ignore default configuration module.',
+ default=True, action='store_false')
+ add('-p', '--python-tree', dest='pytree',
+ help='Print python object tree to stderr.',
+ default=False, action='store_true')
+ add('-r', '--no-color', dest='nocolor',
+ help='Disable color output.' +\
+ (' No effect on Win OS.' if isWindows() else ''),
+ default=False, action='store_true')
+ add('-s', '--skip-source', dest='skipsource',
+ help='Skip writing translated source; useful when printing trees',
+ default=False, action='store_true')
+ add('-t', '--lexer-tokens', dest='lexertokens',
+ help='Print lexer tokens to stderr.',
+ default=False, action='store_true')
+ add('-v', '--version', action='version', version='%(prog)s ' + version)
+
+ ns = parser.parse_args(argv)
+ if ns.inputfile == '-':
+ ns.inputfile = sys.stdin
+ if ns.outputfile == '-':
+ ns.outputfile = sys.stdout
+
+ configColors(ns.nocolor)
+ configLogging(ns.loglevel)
+ return ns
+
+
+if __name__ == '__main__':
+ sys.exit(runMain(configScript(sys.argv[1:])))
diff --git a/java2python/compiler/visitor.py b/java2python/compiler/visitor.py
index f62e53e..c798c7c 100644
--- a/java2python/compiler/visitor.py
+++ b/java2python/compiler/visitor.py
@@ -35,6 +35,8 @@ class Base(object):
def accept(self, node, memo):
""" Accept a node, possibly creating a child visitor. """
+ if node.token is None:
+ return # FIXME
tokType = tokens.map.get(node.token.type)
missing = lambda node, memo:self
call = getattr(self, 'accept{0}'.format(tokens.title(tokType)), missing)
@@ -45,7 +47,7 @@ def accept(self, node, memo):
def insertComments(self, tmpl, tree, index, memo):
""" Add comments to the template from tokens in the tree. """
prefix = self.config.last('commentPrefix', '# ')
- cache, parser, comTypes = memo.comments, tree.parser, tokens.commentTypes
+ cache, parser, comTypes = memo.comments, tree.parser if hasattr(tree, "parser") else None, tokens.commentTypes
comNew = lambda t:t.type in comTypes and (t.index not in cache)
for tok in ifilter(comNew, parser.input.tokens[memo.last:index]):
@@ -75,10 +77,12 @@ def stripComment(self, text):
def walk(self, tree, memo=None):
""" Depth-first visiting of the given AST. """
- if not tree:
+ if not tree or not hasattr(tree, "type"):
return
memo = Memo() if memo is None else memo
- comIns = self.insertComments
+ def test(*args, **kwargs):
+ pass
+ comIns = test #self.insertComments
comIns(self, tree, tree.tokenStartIndex, memo)
visitor = self.accept(tree, memo)
if visitor:
@@ -86,7 +90,7 @@ def walk(self, tree, memo=None):
visitor.walk(child, memo)
comIns(visitor, child, child.tokenStopIndex, memo)
comIns(self, tree, tree.tokenStopIndex, memo)
- if tree.isJavaSource:
+ if getattr(tree, "isJavaSource", False):
comIns(self, tree, len(tree.parser.input.tokens), memo)
# fixme: we're calling the mutators far too frequently instead
# of only once per object after its walk is finished.
@@ -742,11 +746,18 @@ def acceptPrePost(self, node, memo):
if node.withinExpr:
name = node.firstChildOfType(tokens.IDENT).text
handler = self.configHandler('VariableNaming')
- rename = handler(name)
- block = self.parents(lambda x:x.isMethod).next()
- if pre:
+
+ left = None # FIXME: handler can be None.
+ rename = None
+ if handler is None:
left = name
else:
+ rename = handler(name)
+
+ block = self.parents(lambda x: x.isMethod).next()
+ if pre:
+ left = name
+ elif left is None:
left = rename
block.adopt(factory(fs=FS.l+' = '+FS.r, left=rename, right=name))
self.left = factory(parent=self, fs=FS.l, left=left)
diff --git a/java2python/lang/JavaLexer.py b/java2python/lang/JavaLexer.py
index 9c1725a..0a73c42 100644
--- a/java2python/lang/JavaLexer.py
+++ b/java2python/lang/JavaLexer.py
@@ -1,9 +1,17 @@
# $ANTLR 3.1.3 Mar 18, 2009 10:09:25 Java.g 2012-01-29 13:54:05
+import re
import sys
from antlr3 import *
from antlr3.compat import set, frozenset
+def version_str_to_tuple(version_str):
+ """Convert a version string into a tuple of integers."""
+ # Extract numeric parts of the version string
+ numbers = re.findall(r'\d+', version_str)
+ # Convert numeric strings to integers and return as a tuple
+ return tuple(map(int, numbers))
+
# for convenience in actions
HIDDEN = BaseRecognizer.HIDDEN
diff --git a/java2python/lang/JavaParser.py b/java2python/lang/JavaParser.py
index 28b9c64..57802af 100644
--- a/java2python/lang/JavaParser.py
+++ b/java2python/lang/JavaParser.py
@@ -1,5 +1,6 @@
# $ANTLR 3.1.3 Mar 18, 2009 10:09:25 Java.g 2012-01-29 13:54:04
+import re
import sys
from antlr3 import *
from antlr3.compat import set, frozenset
@@ -7,6 +8,12 @@
from antlr3.tree import *
+def version_str_to_tuple(version_str):
+ """Convert a version string into a tuple of integers."""
+ # Extract numeric parts of the version string
+ numbers = re.findall(r'\d+', version_str)
+ # Convert numeric strings to integers and return as a tuple
+ return tuple(map(int, numbers))
# for convenience in actions
HIDDEN = BaseRecognizer.HIDDEN
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..8bfd5a1
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build =
+tag_date = 0
+