├── .gitignore ├── bin └── j2py ├── doc ├── customization.md ├── install.md ├── intro.md ├── readme.md ├── tests.md ├── translation.md └── usage.md ├── java2python ├── __init__.py ├── compiler │ ├── __init__.py │ ├── block.py │ ├── template.py │ └── visitor.py ├── config │ ├── __init__.py │ └── default.py ├── lang │ ├── Java.g │ ├── Java.tokens │ ├── JavaDoc.g │ ├── JavaLexer.py │ ├── JavaParser.py │ ├── Makefile │ ├── __init__.py │ ├── base.py │ └── selector.py ├── lib │ └── __init__.py └── mod │ ├── __init__.py │ ├── basic.py │ ├── include │ ├── __init__.py │ ├── bsr.py │ ├── classmethod.py │ ├── overloading.py │ ├── sync.py │ └── sync_test.py │ └── transform.py ├── license.txt ├── readme.md ├── setup.py └── test ├── Anno0.java ├── Anno1.java ├── Anno2.java ├── Anno3.java ├── Array0.java ├── Array1.java ├── Array2.java ├── Array3.java ├── Assert0.java ├── Assign0.java ├── Assign1.java ├── BasicTypes0.java ├── BasicTypes1.java ├── BasicTypes2.java ├── BasicTypes3.java ├── Break0.java ├── Break1.java ├── Cast0.java ├── Class00.java ├── Class01.java ├── Class02.java ├── Class03.java ├── Class04.java ├── Class05.java ├── Class06.java ├── Class07.java ├── Class08.java ├── Class09.java ├── Class10.java ├── Class11.java ├── Class12.java ├── Class13.java ├── Comments0.java ├── Comments1.java ├── Comments2.java ├── Comments3.java ├── Comments4.java ├── Continue0.java ├── Continue1.java ├── Continue2.java ├── Ctor0.java ├── Ctor1.java ├── Ctor2.java ├── Ctor3.java ├── DoWhile0.java ├── DoWhile1.java ├── Enum0.java ├── Enum1.java ├── Exception0.java ├── Expr0.java ├── Expr1.java ├── Expr2.java ├── ForEach0.java ├── ForLoop0.java ├── ForLoop1.java ├── ForLoop2.java ├── Format0.java ├── Format1.java ├── GenericPairs0.java ├── If0.java ├── If1.java ├── If2.java ├── If3.java ├── If4.java ├── If5.java ├── If6.java ├── If7.java ├── If8.java ├── Interface0.java ├── Interface1.java ├── Interface2.java ├── JavaDoc0.java ├── Keywords0.java ├── Length0.java ├── Literals0.java ├── Makefile ├── Math0.java ├── Package0 ├── Class0.java ├── Class0.py └── __init__.py ├── Property0.java ├── Property1.java ├── Self0.java ├── String0.java ├── Super0.java ├── Switch0.java ├── Switch1.java ├── Switch2.java ├── Switch3.java ├── Switch4.java ├── Switch5.java ├── Synchronized0.java ├── Synchronized1.java ├── Synchronized2.java ├── Ternary0.java ├── Throw0.java ├── Try0.java ├── TypeTransform0.java ├── UsePackage0.java ├── VariadicMethod0.java ├── VoidClass0.java ├── While0.java ├── While1.java ├── While2.java ├── altconfigs └── Class10.py ├── configs ├── Cast0.py ├── Class00.py ├── Class10.py ├── GenericPairs0.py ├── Interface3.py ├── UsePackage0.py ├── __init__.py └── defaults.py ├── other_config_a.py ├── other_config_b.py ├── runj2py ├── runjava └── selector ├── Makefile ├── Selector1.java └── test_all.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.egg-info 3 | *.pyc 4 | -------------------------------------------------------------------------------- /bin/j2py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ j2py -> Java to Python compiler script. 4 | 5 | This is all very ordinary. We import the package bits, open and read 6 | a file, translate it, and write it out. 7 | 8 | """ 9 | import sys 10 | from argparse import ArgumentParser, ArgumentTypeError 11 | from collections import defaultdict 12 | from logging import _levelNames as logLevels, exception, warning, info, basicConfig 13 | from os import path, makedirs 14 | from time import time 15 | 16 | from java2python.compiler import Module, buildAST, transformAST 17 | from java2python.config import Config 18 | from java2python.lib import escapes 19 | 20 | 21 | version = '0.5.1' 22 | 23 | 24 | def logLevel(value): 25 | """ Returns a valid logging level or raises and exception. """ 26 | msg = 'invalid loglevel: %r' 27 | try: 28 | lvl = int(value) 29 | except (ValueError, ): 30 | name = value.upper() 31 | if name not in logLevels: 32 | raise ArgumentTypeError(msg % value) 33 | lvl = logLevels[name] 34 | else: 35 | if lvl not in logLevels: 36 | raise ArgumentTypeError(msg % value) 37 | return lvl 38 | 39 | 40 | def configFromDir(inname, dirname): 41 | """ Returns a file name from the given config directory. """ 42 | name = path.join(dirname, path.basename(path.splitext(inname)[0])) 43 | return '%s.py' % path.abspath(name) 44 | 45 | 46 | def runMain(options): 47 | """ Runs our main function with profiling if indicated by options. """ 48 | if options.profile: 49 | import cProfile, pstats 50 | prof = cProfile.Profile() 51 | prof.runcall(runOneOrMany, options) 52 | stats = pstats.Stats(prof, stream=sys.stderr) 53 | stats.strip_dirs().sort_stats('cumulative') 54 | stats.print_stats().print_callers() 55 | return 0 56 | else: 57 | return runOneOrMany(options) 58 | 59 | def runOneOrMany(options): 60 | """ Runs our main transformer with each of the input files. """ 61 | infile, outfile = options.inputfile, options.outputfile 62 | 63 | if infile and not isinstance(infile, file) and path.isdir(infile): 64 | if outfile and not isinstance(outfile, file) and not path.isdir(outfile): 65 | warning('Must specify output directory or stdout when using input directory.') 66 | return 2 67 | def walker(arg, dirname, files): 68 | for name in [name for name in files if name.endswith('.java')]: 69 | fullname = path.join(dirname, name) 70 | options.inputfile = fullname 71 | info('opening %s', fullname) 72 | if outfile and outfile != '-' and not isinstance(outfile, file): 73 | full = path.abspath(path.join(outfile, fullname)) 74 | head, tail = path.split(full) 75 | tail = path.splitext(tail)[0] + '.py' 76 | if not path.exists(head): 77 | makedirs(head) 78 | options.outputfile = path.join(head, tail) 79 | runTransform(options) 80 | path.walk(infile, walker, None) 81 | return 0 82 | else: 83 | return runTransform(options) 84 | 85 | 86 | def runTransform(options): 87 | """ Compile the indicated java source with the given options. """ 88 | timed = defaultdict(time) 89 | timed['overall'] 90 | 91 | filein = fileout = filedefault = '-' 92 | if options.inputfile and not isinstance(options.inputfile, file): 93 | filein = options.inputfile 94 | if options.outputfile and not isinstance(options.outputfile, file): 95 | fileout = options.outputfile 96 | elif fileout != filedefault: 97 | fileout = '%s.py' % (path.splitext(filein)[0]) 98 | 99 | configs = options.configs 100 | if options.configdirs and not isinstance(filein, file): 101 | for configdir in options.configdirs: 102 | dirname = configFromDir(filein, configdir) 103 | if path.exists(dirname): 104 | configs.insert(0, dirname) 105 | if options.includedefaults: 106 | configs.insert(0, 'java2python.config.default') 107 | 108 | try: 109 | if filein != '-': 110 | source = open(filein).read() 111 | else: 112 | source = sys.stdin.read() 113 | except (IOError, ), exc: 114 | code, msg = exc.args[0:2] 115 | print 'IOError: %s.' % (msg, ) 116 | return code 117 | 118 | timed['comp'] 119 | try: 120 | tree = buildAST(source) 121 | except (Exception, ), exc: 122 | exception('exception while parsing') 123 | return 1 124 | timed['comp_finish'] 125 | 126 | config = Config(configs) 127 | timed['xform'] 128 | transformAST(tree, config) 129 | timed['xform_finish'] 130 | 131 | timed['visit'] 132 | module = Module(config) 133 | module.sourceFilename = path.abspath(filein) if filein != '-' else None 134 | module.name = path.splitext(path.basename(filein))[0] if filein != '-' else '' 135 | module.walk(tree) 136 | timed['visit_finish'] 137 | 138 | timed['encode'] 139 | source = unicode(module) 140 | timed['encode_finish'] 141 | timed['overall_finish'] 142 | 143 | if options.lexertokens: 144 | for idx, tok in enumerate(tree.parser.input.tokens): 145 | print >> sys.stderr, '{0} {1}'.format(idx, tok) 146 | print >> sys.stderr 147 | 148 | if options.javaast: 149 | tree.dump(sys.stderr) 150 | print >> sys.stderr 151 | 152 | if options.pytree: 153 | module.dumpRepr(sys.stderr) 154 | print >> sys.stderr 155 | 156 | if not options.skipsource: 157 | if fileout == filedefault: 158 | output = sys.stdout 159 | else: 160 | output = open(fileout, 'w') 161 | module.name = path.splitext(filein)[0] if filein != '-' else '' 162 | print >> output, source 163 | 164 | if not options.skipcompile: 165 | try: 166 | compile(source, '', 'exec') 167 | except (SyntaxError, ), ex: 168 | warning('Generated source has invalid syntax. %s', ex) 169 | else: 170 | info('Generated source has valid syntax.') 171 | 172 | info('Parse: %.4f seconds', timed['comp_finish'] - timed['comp']) 173 | info('Visit: %.4f seconds', timed['visit_finish'] - timed['visit']) 174 | info('Transform: %.4f seconds', timed['xform_finish'] - timed['xform']) 175 | info('Encode: %.4f seconds', timed['encode_finish'] - timed['encode']) 176 | info('Total: %.4f seconds', timed['overall_finish'] - timed['overall']) 177 | return 0 178 | 179 | 180 | def isWindows(): 181 | """ True if running on Windows. """ 182 | return sys.platform.startswith('win') 183 | 184 | 185 | def configLogging(loglevel): 186 | """ Configure the logging package. """ 187 | fmt = '# %(levelname)s %(funcName)s: %(message)s' 188 | basicConfig(level=loglevel, format=fmt) 189 | 190 | 191 | def configColors(nocolor): 192 | """ Configure the color escapes. """ 193 | if isWindows() or nocolor: 194 | escapes.clear() 195 | 196 | 197 | def configScript(argv): 198 | """ Return an options object from the given argument sequence. """ 199 | parser = ArgumentParser( 200 | description='Translate Java source code to Python.', 201 | epilog='Refer to https://github.com/natural/java2python for docs and support.' 202 | ) 203 | 204 | add = parser.add_argument 205 | add(dest='inputfile', nargs='?', 206 | help='Read from INPUT. May use - for stdin (default).', 207 | metavar='INPUT', default=None) 208 | add(dest='outputfile', nargs='?', 209 | help='Write to OUTPUT. May use - for stdout (default).', 210 | metavar='OUTPUT', default=None) 211 | add('-c', '--config', dest='configs', 212 | help='Use CONFIG file or module. May be repeated.', 213 | metavar='CONFIG', default=[], action='append') 214 | add('-d', '--config-dir', dest='configdirs', 215 | help='Use DIR to match input filename with config filename.', 216 | metavar='DIR', default=[], action='append') 217 | add('-f', '--profile', dest='profile', 218 | help='Profile execution and print results to stderr.', 219 | default=False, action='store_true') 220 | add('-j', '--java-ast', dest='javaast', 221 | help='Print java source AST tree to stderr.', 222 | default=False, action='store_true') 223 | add('-k', '--skip-compile', dest='skipcompile', 224 | help='Skip compile check on translated source.', 225 | default=False, action='store_true') 226 | add('-l', '--log-level', dest='loglevel', 227 | help='Set log level by name or value.', 228 | default='WARN', type=logLevel) 229 | add('-n', '--no-defaults', dest='includedefaults', 230 | help='Ignore default configuration module.', 231 | default=True, action='store_false') 232 | add('-p', '--python-tree', dest='pytree', 233 | help='Print python object tree to stderr.', 234 | default=False, action='store_true') 235 | add('-r', '--no-color', dest='nocolor', 236 | help='Disable color output.' +\ 237 | (' No effect on Win OS.' if isWindows() else ''), 238 | default=False, action='store_true') 239 | add('-s', '--skip-source', dest='skipsource', 240 | help='Skip writing translated source; useful when printing trees', 241 | default=False, action='store_true') 242 | add('-t', '--lexer-tokens', dest='lexertokens', 243 | help='Print lexer tokens to stderr.', 244 | default=False, action='store_true') 245 | add('-v', '--version', action='version', version='%(prog)s ' + version) 246 | 247 | ns = parser.parse_args(argv) 248 | if ns.inputfile == '-': 249 | ns.inputfile = sys.stdin 250 | if ns.outputfile == '-': 251 | ns.outputfile = sys.stdout 252 | 253 | configColors(ns.nocolor) 254 | configLogging(ns.loglevel) 255 | return ns 256 | 257 | 258 | if __name__ == '__main__': 259 | sys.exit(runMain(configScript(sys.argv[1:]))) 260 | -------------------------------------------------------------------------------- /doc/customization.md: -------------------------------------------------------------------------------- 1 | ## Customization 2 | 3 | The java2python compiler defers a significant amount of its processing to 4 | handlers defined within configuration files. These configuration files, 5 | directories, and modules are supplied to the `j2py` script on the command 6 | line. See the [usage][] page for instructions on specifying additional configs. 7 | 8 | The default configuration module is `java2python.config.default`. Refer to 9 | [the source of that module][1] for details and additional descriptions. 10 | 11 | 12 | ### Usage 13 | 14 | To change the behavior of some or all of these config items, create a Python 15 | file, define in it the items you want, and specify that file when invoking 16 | `j2py`. 17 | 18 | For example, if you would like to change the comment prefix to `##`, you might 19 | do this: 20 | 21 | $ echo "indentPrefix = '##'" >> ./myconfig.py 22 | 23 | Then run the script: 24 | 25 | $ j2py SomeJavaSource.java -c ./myconfig.py 26 | 27 | The config files are Python modules, so you can use the full power of Python 28 | when writing them. 29 | 30 | 31 | ### Defaults 32 | 33 | Many of the defaults are built using values imported from the 34 | `java2python.mod.basic` module. Refer to the [source of that module][2] for 35 | details. The `java2python.mod` subpackage contains other modules with 36 | additional config handlers. 37 | 38 | 39 | ### A Note About Some of the Names: Prologue, Base, Head, and Epilogue 40 | 41 | When a config point has `Prologue` in its name, it means that the item will be 42 | responsible for generating code before the output. For example, method 43 | prologue handlers generate decorators, while module prologue handlers generate 44 | the shebang line. 45 | 46 | When a config point has `Base` in the name, it means that the item will be 47 | responsible for generating the base classes of a class, enum, or interface. 48 | 49 | A config point with `Head` in the name means that the item will be responsible 50 | for generating code for the section between the declaration and the body of the 51 | item. For example: 52 | 53 | class X(object): 54 | """ this is a comment generated by classHeadHandlers """ 55 | 56 | Finally, when a config point contains `Epilogue`, it means that the item will 57 | be responsible for generating code after the body of the item. The only 58 | recognized epilogue config point is `moduleEpilogueHandlers`, which (by 59 | default) generates a main script stanza if necessary. 60 | 61 | 62 | ### Override vs. Replace 63 | 64 | Many of the config handlers in the default config module are lists or 65 | dictionaries. It may be desirable for your project to supplement or modify 66 | these instead of changing them completely. For example, you could add a module 67 | prologue handler to the existing values. To do so, you would do something like this 68 | in your config: 69 | 70 | from java2python.config.default import modulePrologueHandlers 71 | 72 | def myPrologue(module): 73 | ... 74 | 75 | modulePrologueHandlers.append(myPrologue) 76 | 77 | Values can be removed in a similar way: 78 | 79 | from java2python.config.default import modulePrologueHandlers 80 | from java2python.mod import basic 81 | 82 | modulePrologueHandlers.remove(basic.shebangLine) 83 | 84 | In other cases, you can simply redefine the config value altogether: 85 | 86 | classHeadHandlers = [myCustomDocStringGenerator] 87 | 88 | 89 | ### Customization Points 90 | 91 | The remainder of this page lists the recognized config points, their meaning, 92 | and their default values. 93 | 94 | 95 | #### indentPrefix 96 | 97 | Leading indent character or characters. Four spaces are the default because 98 | that is the recommendation of [PEP 8][]. 99 | 100 | Default: ` ` (four spaces) 101 | 102 | 103 | #### commentPrefix 104 | 105 | Prefix character or characters for comments. The hash+space is recommended by 106 | [PEP 8][]. 107 | 108 | Default: `# ` (hash + space) 109 | 110 | 111 | #### expressionVariableNamingHandler 112 | 113 | When the compiler needs to make up a variable name (for example, to emulate 114 | assignment expressions), it calls this handler to produce a new one. 115 | 116 | Default: `basic.globalNameCounter` 117 | 118 | 119 | #### modulePrologueHandlers 120 | 121 | These values are strings or generators that yield strings for a module 122 | prologue. 123 | 124 | Default: 125 | ``` 126 | [basic.shebangLine, 127 | basic.simpleDocString, 128 | basic.maybeBsr, 129 | basic.maybeSyncHelpers 130 | ] 131 | ``` 132 | 133 | 134 | #### moduleEpilogueHandlers 135 | 136 | These generators yield lines for a module epilogue. 137 | 138 | Default: `[basic.scriptMainStanza]` 139 | 140 | 141 | #### moduleOutputHandlers 142 | 143 | These generators yield (possibly modified) source strings for a module. The 144 | default handler uses values defined elsewhere in the config, e.g., 145 | `moduleOutputSubs`. 146 | 147 | Default: `[basic.outputSubs]` 148 | 149 | 150 | #### modulePackageDeclarationHandler 151 | 152 | This config item is called to handle package declarations. The default handler simply 153 | turns those declarations into comments. 154 | 155 | Default: `basic.commentedPackages` 156 | 157 | 158 | #### moduleImportDeclarationHandler 159 | 160 | This config item is called to handle import statements. The default handler 161 | transforms the import statements into Python imports. 162 | 163 | Default: `basic.simpleImports` 164 | 165 | 166 | #### moduleOutputSubs 167 | 168 | Mapping of input/output regular expressions used during the final pass of 169 | source generation. 170 | 171 | Default: refer to the [java2python.config.default][1] module. 172 | 173 | 174 | #### classHeadHandlers 175 | 176 | These generators yield doc values for the head of classes. 177 | 178 | Default: `[basic.simpleDocString]` 179 | 180 | 181 | #### classBaseHandlers 182 | 183 | These generators yield the base types (as strings) for classes. 184 | 185 | Default: `[basic.defaultBases]` 186 | 187 | 188 | #### classPostWalkHandlers 189 | 190 | These handlers are called with each class object after it has been completely 191 | constructed. 192 | 193 | Default: `[]` 194 | 195 | 196 | #### interfaceBaseHandlers 197 | 198 | These generators yield the base types (as strings) for interfaces. 199 | 200 | Default: `[basic.defaultBases]` 201 | 202 | 203 | #### interfaceHeadHandlers 204 | 205 | These generators yield doc values for the head of interfaces. 206 | 207 | Default: `[basic.simpleDocString, '__metaclass__ = ABCMeta']` 208 | 209 | 210 | #### enumHeadHandlers 211 | 212 | These generators yield doc values for the head of enums. 213 | 214 | Default: `[basic.simpleDocString]` 215 | 216 | 217 | #### enumValueHandler 218 | 219 | This handler is responsible for creating enum values on classes after they've 220 | been defined. 221 | 222 | Default: `basic.enumConstStrings` 223 | 224 | 225 | #### methodParamHandlers 226 | 227 | This handler is responsible for constructing method parameters. 228 | 229 | Default: `[basic.defaultParams]` 230 | 231 | 232 | #### methodLockFunctionName 233 | 234 | This is the name of the callable used to construct locks for an object with the 235 | synchronized keyword. 236 | 237 | Default: `'lock_for_object'` 238 | 239 | 240 | #### methodHeadHandlers 241 | 242 | These generators yield values for the head of classes. 243 | 244 | Default: `[basic.simpleDocString]` 245 | 246 | 247 | #### methodPrologueHandlers 248 | 249 | These generators yield values for the module prologue. 250 | 251 | Default: 252 | 253 | ``` 254 | [basic.maybeAbstractMethod, 255 | basic.maybeClassMethod, 256 | basic.maybeSynchronizedMethod, 257 | basic.overloadedClassMethods, 258 | ] 259 | ``` 260 | 261 | #### astTransforms 262 | 263 | The AST transformer uses these declarations to modify an AST before compiling 264 | it to Python source. 265 | 266 | Default: refer to the [java2python.config.default][1] module. 267 | 268 | #### typeSubs 269 | 270 | Many Java identifiers have a 1:1 relationship with Python identifiers, and this 271 | mapping is used to convert them when found. Note that this mapping is now 272 | unnecessary and will be folded into the `astTransforms` sequence in future 273 | releases. 274 | 275 | [1]: https://github.com/natural/java2python/blob/master/java2python/config/default.py 276 | [2]: https://github.com/natural/java2python/blob/master/java2python/mod/basic.py 277 | [PEP 8]: http://www.python.org/dev/peps/pep-0008/ 278 | [usage]: https://github.com/natural/java2python/tree/master/doc/usage.md 279 | -------------------------------------------------------------------------------- /doc/install.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | ### New School 4 | 5 | Kids these days have it easy: 6 | 7 | # pip install java2python 8 | 9 | ### Old School 10 | 11 | #### Install ANTLR Runtime 12 | 13 | We need the ANTLR Python runtime before we can install java2python: 14 | 15 | # wget http://www.antlr3.org/download/antlr-3.1.3.tar.gz 16 | # tar xfz antlr-3.1.3.tar.gz 17 | # cd antlr-3.1.3/runtime/Python/ 18 | # python setup.py install 19 | 20 | #### Install java2python 21 | 22 | Now the goodness: 23 | 24 | # wget https://github.com/downloads/natural/java2python/java2python-0.5.1.tar.gz 25 | # tar xfz java2python-0.5.1.tar.gz 26 | # cd java2python 27 | # python setup.py install 28 | 29 | ### Development Version 30 | 31 | The latest source can be installed directly from github: 32 | 33 | # pip install --upgrade https://github.com/natural/java2python/zipball/master 34 | 35 | You'll want to clone or fork the repo to work on the project, however. 36 | 37 | 38 | ### Dependencies 39 | 40 | The runtime dependency for java2python is the [Python runtime][] for [ANTLR][]. 41 | The exact version number is very important: java2python requires 42 | [version 3.1.3 of the Python runtime][]. 43 | 44 | The development dependencies (what you need if you're coding java2python) are 45 | [ANTLR][], also version 3.1.3, GNU make, and a JVM. 46 | 47 | 48 | [version 3.1.3 of the Python runtime]: http://www.antlr3.org/download/antlr-3.1.3.tar.gz 49 | [Python runtime]: http://www.antlr.org/wiki/display/ANTLR3/Python+runtime 50 | [ANTLR]: http://www.antlr.org 51 | -------------------------------------------------------------------------------- /doc/intro.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This is an introduction. Just like the title told you it would be. 4 | 5 | ### What it Does 6 | 7 | java2python reads the Java source files you give it and produces somewhat 8 | roughly equivalent Python source code. It tries to make the same decisions you 9 | would if you were porting the code manually. It can perform the translation 10 | faster and more accurately than you could (usually). 11 | 12 | ### Where It's Useful 13 | 14 | java2python can help in two situations. First, if you're doing a one-time port 15 | of a Java project to Python, it can save you a lot of time and effort by 16 | getting you really far really fast. 17 | 18 | Second, if you've got a Java project and you'd like to generate a Python port 19 | and keep the port up to date, you'll find that java2python can help 20 | tremendously. The per-project and per-file configuration system helps out a 21 | lot in this area. 22 | 23 | ### Where It's Not 24 | 25 | Where java2python is not useful is also important. It won't be useful to you 26 | if you expect your newly translated Python code to run correctly the first 27 | time. The platforms are too different and this tool is too limited for that to 28 | happen. Also, you won't find java2python very useful if you expect to convert 29 | Java sources at runtime. I suppose you could try, but I wouldn't. 30 | 31 | ### How it Works 32 | 33 | java2python first converts the source code you give it into an abstract syntax 34 | tree. (That's a lie, really. java2python doesn't do this step, [ANTLR][] does 35 | this step, and [ANTLR][] is a whole lot bigger and cooler than java2python 36 | could ever be. Obviously, really smart people worked on [ANTLR][] and only one 37 | fairly dim one worked on java2python). 38 | 39 | After the syntax tree is constructed, it's walked and its nodes are converted 40 | to their Python equivalents. When the walking is complete, java2python takes a 41 | few more swipes at it and prints it out. It's all very boring, like geology or 42 | watching someone learn to play the xylophone. 43 | 44 | This is all well and good for most cases where there exists a very similar 45 | Python construct for the given Java construct. Classes, for example, are 46 | pretty much the same in both languages. The trouble spots are places where a 47 | construct exists in Java that is not readily available in Python. 48 | 49 | Note: yes, of course, we're dealing with Turing Machines and they're 50 | equivalent. If it works in Java, it can work in Python, and I'm not saying 51 | that it can't. But what I am saying is that there are chunks of Java source 52 | code that you can't make into nice and neat and obvious Python equivalents. 53 | 54 | To get around these trouble spots, java2python takes the approach of trying 55 | make the problem go away. For example, in Java the `if` statement can contain 56 | an assignment expression: 57 | 58 | ```java 59 | if (++x == 0) { ... } 60 | ``` 61 | 62 | There isn't a single statement equivalent in Python because assignments are 63 | statements there, not expressions. So java2python does what it can, presumably 64 | what you would do: 65 | 66 | ```python 67 | x += 1 68 | if x == 0: 69 | ... 70 | ``` 71 | 72 | Careful readers will have spotted just how close we came to driving over a 73 | cliff with that `++x` expression. If the increment had been done on the other 74 | side of the variable, the meaning of the statement would have changed and the 75 | Python code would have been wrong. Fortunately, I've driven by lots of cliffs 76 | and have been scared by all of them so I thought of this ahead of time and 77 | decided to do something about it: 78 | 79 | ```java 80 | if (x++ ==0) { ... } 81 | ``` 82 | 83 | will translate to: 84 | 85 | ```python 86 | mangled_name_for_x = x 87 | x += 1 88 | if mangled_name_for_x == 0: 89 | ... 90 | ``` 91 | 92 | See what java2python did there? It tried to do what you would do. For further 93 | explanation and enumeration see the [translation details][] page. 94 | 95 | 96 | ### Why Bother? 97 | 98 | I bothered to write this because [I needed a Java package][1] to run on the CPython 99 | interpreter. I got tired of porting by hand so I wrote this instead. And 100 | it's an interesting problem (kind of). 101 | 102 | 103 | [ANTLR]: http://www.antlr.org 104 | [translation details]: https://github.com/natural/java2python/tree/master/doc/translation.md 105 | [1]: http://roundrockriver.wordpress.com/2007/02/15/automated-translation-of-java-to-python/ 106 | -------------------------------------------------------------------------------- /doc/readme.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | #### Introduction 4 | 5 | The [Introduction][] provides a brief overview of the package. You should read 6 | this first. 7 | 8 | #### Installation 9 | 10 | The [Installation][] doc describes how to install the package. 11 | 12 | #### Translation Details 13 | 14 | The [Translation Details][] page documents how the package translates Java 15 | syntax to Python. 16 | 17 | #### Usage 18 | 19 | The [Usage][] page explains how to run the `j2py` script. 20 | 21 | 22 | #### Customization 23 | 24 | The [Customization][] doc describes how to customize translation behavior. 25 | 26 | 27 | #### Tests 28 | 29 | The [Tests][] page documents the test suite. 30 | 31 | 32 | [Customization]: https://github.com/natural/java2python/tree/master/doc/customization.md 33 | [Installation]: https://github.com/natural/java2python/tree/master/doc/install.md 34 | [Introduction]: https://github.com/natural/java2python/tree/master/doc/intro.md 35 | [Translation Details]: https://github.com/natural/java2python/tree/master/doc/translation.md 36 | [Usage]: https://github.com/natural/java2python/tree/master/doc/usage.md 37 | [Tests]: https://github.com/natural/java2python/tree/master/doc/tests.md 38 | -------------------------------------------------------------------------------- /doc/tests.md: -------------------------------------------------------------------------------- 1 | ## Tests 2 | 3 | The java2python package includes a [test suite][] for exercising the compiler and 4 | its various translation features. This doc explains how the tests work, how to 5 | run these suite, and how to add new tests to it. 6 | 7 | ### How the Test Suite Works 8 | 9 | The test suite is a [makefile][] that finds `.java` files in the same directory, 10 | converts each to Python, runs both programs, and then compares their output. If 11 | the output matches, the test is considered successful. If not, it's considered 12 | a failure. 13 | 14 | ### How to Run the Test Suite 15 | 16 | The simplest way to run the suite is to run all of it: 17 | 18 | ```bash 19 | $ cd some_path_to/java2python/test 20 | $ make 21 | ``` 22 | 23 | This will print lines like this: 24 | 25 | ``` 26 | ... 27 | [PASS] Class00 28 | [PASS] Class01 29 | [PASS] Class02 30 | ... 31 | ``` 32 | 33 | You can also run an individual test like this: 34 | 35 | ```bash 36 | $ make Class02 37 | [PASS] Class02 38 | ``` 39 | 40 | Notice that there isn't a suffix to the file name; you don't run `make 41 | Class02.java`, just `make Class02`. If you supply an extension, nothing will 42 | happen and the test won't run. 43 | 44 | The `test` directory contains two helper scripts that you can use during 45 | development. The first is [runjava][], which runs the Java compiler and the 46 | Java VM with the indicated file. Use it like this: 47 | 48 | ```bash 49 | $ ./runjava Class01.java 50 | Hello, world. 51 | ``` 52 | 53 | The second script is [runj2py][], which is a handy shortcut for running the 54 | `j2py` script with preset command line arguments for the test configuration. 55 | You run it like this: 56 | 57 | ```bash 58 | $ ./runj2py Class01.java 59 | #!/usr/bin/env python 60 | """ generated source for module Class01 """ 61 | class Class01(object): 62 | ... 63 | ``` 64 | 65 | ### Adding New Tests 66 | 67 | When a new compiler feature is added, or when the translation semantics change, 68 | it's a good idea to add one or more tests to the test suite. Follow this 69 | general outline: 70 | 71 | 1. Create a Java source file that exhibits the language feature in question. 72 | 73 | 2. Name the Java source file `FeatureNN` where `NN` is the next number in 74 | sequence for `Feature`, e.g., `Class14.java`. 75 | 76 | 3. In your Java source, write one or more values to stdout with 77 | `System.out.println`. 78 | 79 | 4. Check the comparison via `make FeatureNN`. If the test passes, it might 80 | indicate the new feature is working correctly. 81 | 82 | [test suite]: https://github.com/natural/java2python/tree/master/test/ 83 | [makefile]: https://github.com/natural/java2python/blob/master/test/Makefile 84 | [runjava]: https://github.com/natural/java2python/blob/master/test/runjava 85 | [runj2py]: https://github.com/natural/java2python/blob/master/test/runj2py 86 | -------------------------------------------------------------------------------- /doc/translation.md: -------------------------------------------------------------------------------- 1 | ## Translation Features 2 | 3 | 4 | ### General Approach 5 | 6 | The approach taken by java2python is to favor readability over correctness. 7 | 8 | ### Identifiers and Qualified Identifiers 9 | 10 | java2python copies identifiers from source to target, modifying the value only 11 | when: 12 | 13 | * the identifier conflicts with a Python keyword or builtin, or 14 | * the identifier has an explicit lexical transformation 15 | 16 | 17 | ### Literals: Integer, Floating Point, Character, String, Boolean and Null 18 | 19 | Literals are copied from source to target with the following modifications: 20 | 21 | * `null` is changed to `None` 22 | * `false` is changed to `False` 23 | * `true` is changed to `True` 24 | * if necessary, floating point literals are changed to valid Python values 25 | * string and character literals are changed to Python strings 26 | 27 | Transformation of literal values happens at the AST level; see the 28 | [`astTransforms`][1] configuration value for details. 29 | 30 | ### Expressions 31 | 32 | #### Constant Expressions 33 | 34 | Constant expressions are translated to their Python equivalents. 35 | 36 | #### Ternary Expressions 37 | 38 | Ternary expressions are translated to their Python form (`val if condition else 39 | other`) 40 | 41 | 42 | #### Prefix Operators 43 | 44 | All of the Java prefix operators are supported: 45 | 46 | ++ -- ! ~ + - 47 | 48 | In the case of `++` and `--`, java2python translates to `+= 1` and `-= 1`. If 49 | necessary, those expressions are moved outside of statements. 50 | 51 | #### Assignment Operators 52 | 53 | All of the following assignment operators are translated into their Python 54 | equivalents: 55 | 56 | = += -= *= /= &= |= ^= %= <<= >>= 57 | 58 | The bit shift right (`>>>`)and bit shift assign right (`>>>=`) operators are 59 | mapped to a function; if java2python detects code that uses either of these, it 60 | replaces the operator with that function and includes the function within the 61 | output. This behavior is controlled by the [`modulePrologueHandlers`][6] config 62 | handler. 63 | 64 | #### Infix Operators 65 | 66 | The following operators are translated to their Python equivalents: 67 | 68 | || && | ^ & == != < > 69 | <= >= << >> >>> + - * / % 70 | 71 | Refer to the note above regarding bit shift right. 72 | 73 | ### Basic Types 74 | 75 | The basic Java types are mapped to Python types as follows: 76 | 77 | * `byte`, `short`, `int`, and `long` become `int` 78 | * `char` becomes `str` 79 | * `float` and `double` become `float` 80 | * `boolean` becomes `bool` 81 | 82 | #### Arrays 83 | 84 | Java arrays and array access expressions are translated to their Python 85 | equivalents. 86 | 87 | 88 | ### Types, Interfaces, Enums 89 | 90 | Java classes, interfaces, and enums are translated into Python classes. 91 | 92 | In the case of interfaces, the strategy is configurable. By default, 93 | interfaces are translated to classes utilizing the `ABCMeta` class. The 94 | package includes config handlers that can translate to simple classes 95 | (inheriting from `object`), or from Zope Interfaces. Interface base types are 96 | controlled via the [`interfaceBaseHandlers`][2] config item. The 97 | [`interfaceHeadHandlers`][3] config item controls the metaclass. 98 | 99 | Enums are also translated via a configurable strategy. By default, enumerated 100 | values are created as class attributes with string values. The package 101 | includes a config handler to create class attributes with integer values. The 102 | config handler that controls enumeration value construction is 103 | [`enumValueHandler`][4]. 104 | 105 | 106 | ### Statements 107 | 108 | #### assert 109 | 110 | Java `assert` statements are translated to equivalent Python `assert` 111 | statements. 112 | 113 | #### if 114 | 115 | Java `if` statements are translated to equivalent Python `if` statements. 116 | 117 | #### import 118 | 119 | The processing import statements is delegated to the [`moduleImportDeclarationHandler`][9]. 120 | 121 | #### for 122 | 123 | Java `for` statements are translated to equivalent Python `for` statements. 124 | 125 | #### while and do 126 | 127 | Java `while` and `do` statements are translated to equivalent Python `while` 128 | statements. 129 | 130 | #### try and catch 131 | 132 | Java `try` and `catch` statements are translated to equivalent Python `try` and 133 | `except` statements. 134 | 135 | #### switch and case 136 | 137 | Java `switch` and `case` statements are translated to equivalent Python `if` 138 | statements. 139 | 140 | #### synchronized 141 | 142 | In the case of a `synchronized` method or static method, the compiler will 143 | include a decorator, `@synchronized` in the method or static method preamble. 144 | In the case of a `synchronized` block, the compiler will translate to this 145 | form: 146 | 147 | with lock_for_object(expr): 148 | ... 149 | 150 | The `lock_for_object` callable is the default and can be controlled via the 151 | [`methodLockFunctionName`][5] config item. Also of note, the default 152 | [`modulePrologueHandlers`][6] uses a generator named `maybeSyncHelpers` to include 153 | Python helper code for synchronization. 154 | 155 | #### return 156 | 157 | Java `return` statements are translated to equivalent Python `return` 158 | statements. 159 | 160 | 161 | #### throw 162 | 163 | Java `throw` statements are translated to equivalent Python `raise` statements. 164 | 165 | #### break 166 | 167 | Java `break` statements are translated to equivalent Python `break` statements. 168 | However, a Java `break` statement with an identifier (e.g., `break FOO`) is not 169 | supported. If the compiler detects such a statement, a warning will be printed 170 | and the translated source will not contain the original label. 171 | 172 | #### continue 173 | 174 | Java `continue` statements are translated to equivalent Python `continue` 175 | statements. However, a Java `continue` statement with an identifier (e.g., 176 | `continue FOO`) is not supported. If the compiler detects such a statement, a 177 | warning will be printed and the translated source will not contain the original 178 | label. 179 | 180 | 181 | ### Other Keywords 182 | 183 | #### this 184 | 185 | The `this` Java keyword is translated to the Python pseudo keyword `self`. 186 | 187 | #### instanceof 188 | 189 | The `instanceof` Java keyword is translated to the `isinstance(…)` Python 190 | function call. 191 | 192 | #### super 193 | 194 | The Java keyword `super` is translated to the `super(…)` Python function call. 195 | 196 | #### .class 197 | 198 | The compiler translates Java `.class` expressions to `.__class__` attribute 199 | references. 200 | 201 | #### void 202 | 203 | The Java keyword `void` is typically discarded by the compiler. In the case of 204 | the `void.class` form, the compiler translates the expression to 205 | `None.__class__`. 206 | 207 | 208 | ### Annotations 209 | 210 | Annotations are typically dropped by the compiler. The following Java 211 | annotations have little or no meaning in Python and are discarded: 212 | 213 | public protected private abstract final native transient 214 | volatile strictfp 215 | 216 | #### static 217 | 218 | The `static` annotation is translated to a `@classmethod` decorator for the 219 | corresponding method. 220 | 221 | #### synchronized 222 | 223 | When used as a method or static method annotation, the `synchronized` keyword 224 | is translated to a `@synchronized` method decorator. This behavior is 225 | controllable via the [`methodPrologueHandlers`][7] config item. 226 | 227 | See the note above regarding the use of `synchronized` within blocks. 228 | 229 | ### Comments 230 | 231 | Both Java end-of-line comments and multi-line comments are translated to Python 232 | comments. The comment prefix is `# ` (hash plus space) by default, and is 233 | controllable via the [`commentPrefix`][8] config item. 234 | 235 | #### JavaDoc 236 | 237 | JavaDoc comments are preserved as Python comments. 238 | 239 | 240 | ### References 241 | 242 | Java language specification: http://java.sun.com/docs/books/jls/third_edition/html/syntax.html 243 | 244 | 245 | [1]: https://github.com/natural/java2python/tree/master/doc/customization.md#astTransforms 246 | [2]: https://github.com/natural/java2python/tree/master/doc/customization.md#interfaceBaseHandlers 247 | [3]: https://github.com/natural/java2python/tree/master/doc/customization.md#interfaceHeadHandlers 248 | [4]: https://github.com/natural/java2python/tree/master/doc/customization.md#enumValueHandler 249 | [5]: https://github.com/natural/java2python/tree/master/doc/customization.md#methodLockFunctionName 250 | [6]: https://github.com/natural/java2python/tree/master/doc/customization.md#modulePrologueHandlers 251 | [7]: https://github.com/natural/java2python/tree/master/doc/customization.md#methodPrologueHandlers 252 | [8]: https://github.com/natural/java2python/tree/master/doc/customization.md#commentPrefix 253 | [9]: https://github.com/natural/java2python/tree/master/doc/customization.md#moduleImportDeclarationHandler 254 | -------------------------------------------------------------------------------- /doc/usage.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | This page describes how to invoke the java2python script, `j2py`. 4 | 5 | 6 | ### Basic Use 7 | 8 | The simplest way to use java2python is with the `j2py` command 9 | and the name of an input file and output file: 10 | 11 | ```bash 12 | $ j2py [INPUT] [OUTPUT] 13 | ``` 14 | 15 | Both are optional, but you'll usually supply an input file: 16 | 17 | ```bash 18 | $ j2py SourceFile.java 19 | ``` 20 | 21 | 22 | ### Options and Arguments 23 | 24 | The `j2py` command accepts options that alter its behavior. 25 | The behavior of the code generator is not part of the command itself; 26 | to change code generation behavior, refer to the [customization][] 27 | page. 28 | 29 | 30 | #### Code Generation 31 | 32 | * `[INPUT]` 33 | 34 | Read from the given file. Specify `-` for `stdin`. If not 35 | given the command will read from `stdin`. 36 | 37 | If `[INPUT]` is a directory, the script will walk the directory looking for 38 | files named `.java`, and transform each one. If `[OUTPUT]` is also a 39 | directory, the directory structure of `[INPUT]` will be recreated below it. 40 | 41 | If `[INPUT]` is a directory, `[OUTPUT]` must also be a directory, or it may 42 | be `-` or unspecified. 43 | 44 | * `[OUTPUT]` 45 | 46 | Write to the given file. Specify `-` for `stdout`. If not 47 | given the command will write to `stdout`. 48 | 49 | * `-l LEVEL`, `--log-level LEVEL` 50 | 51 | Set the logging package to the specified log level. The log level 52 | may given as an integer (e.g., `50` for critical) or by name 53 | (e.g., `CRITICAL`, `Critical`, or `critical`). 54 | 55 | * `-c NAME`, `--config NAME` 56 | 57 | Use the specified configuration module or file. This option may 58 | be repeated. 59 | 60 | Configuration modules/files are referenced in reverse order, i.e., 61 | from the final value given to the first given, with the default 62 | configuration referenced last. 63 | 64 | See the [customization][] page for details of the 65 | configuration system and available configuration points. 66 | 67 | * `-d DIR`, `--config-dir DIR` 68 | 69 | Use the given directory name to match input file names to 70 | configuration file names. This option may be repeated. 71 | 72 | For example, to translate 73 | `FooBar.java` and use the configuration stored in 74 | `./cfg/FooBar.py`, specify `-d ./cfg`. 75 | 76 | * `-k`, `--skip-compile` 77 | 78 | Do not byte compile the output to test for valid Python syntax. 79 | 80 | * `-n`, `--no-defaults` 81 | 82 | Ignore the default configuration module. 83 | 84 | * `-r`, `--no-color` 85 | 86 | Disable colorized output. 87 | 88 | Colorized output is not available on Windows and this option is ignored 89 | there. 90 | 91 | 92 | #### Development 93 | 94 | * `-p`, `--python-tree` 95 | 96 | Print a representation of the internal Python code tree. 97 | Representation is written to `stderr`. 98 | 99 | * `-j`, `--java-ast` 100 | 101 | Print a representation of the Java abstract syntax tree. 102 | Representation is written to `stderr`. 103 | 104 | * `-f`, `--profile` 105 | 106 | Profile execution and print the results to `stderr`. 107 | 108 | * `-s`, `--skip-source` 109 | 110 | Do not write generated source. This most useful in development of 111 | java2python itself and when combined with `-p` and/or 112 | `-j`. 113 | 114 | 115 | #### Meta 116 | 117 | * `-h`, `--help` 118 | 119 | Show a help message and exit 120 | 121 | * `-v`, `--version` 122 | 123 | Show the program version number and exit. 124 | 125 | 126 | 127 | [customization]: https://github.com/natural/java2python/tree/master/doc/customization.md 128 | -------------------------------------------------------------------------------- /java2python/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python -> top-level package marker. 4 | 5 | 6 | -------------------------------------------------------------------------------- /java2python/compiler/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.compiler package marker. 4 | # 5 | # This module provides a simpler facade over the rest of the compiler 6 | # subpackage. Client code should use the values in this module 7 | # instead of using directly referencing items within the subpackage. 8 | 9 | from java2python.compiler.block import Module 10 | from java2python.lang import Lexer, Parser, StringStream, TokenStream, TreeAdaptor 11 | 12 | 13 | def buildAST(source): 14 | """ Returns an AST for the given source. """ 15 | lexer = Lexer(StringStream(source)) 16 | parser = Parser(TokenStream(lexer)) 17 | adapter = TreeAdaptor(lexer, parser) 18 | parser.setTreeAdaptor(adapter) 19 | scope = parser.javaSource() 20 | return scope.tree 21 | 22 | 23 | def buildJavaDocAST(source): 24 | """ Returns an AST for the given javadoc source. """ 25 | from java2python.lang.JavaDocLexer import JavaDocLexer 26 | from java2python.lang.JavaDocParser import JavaDocParser 27 | lexer = JavaDocLexer(StringStream(source)) 28 | parser = JavaDocParser(TokenStream(lexer)) 29 | scope = parser.commentBody() 30 | return scope.tree 31 | 32 | 33 | def transformAST(tree, config): 34 | """ Walk the tree and apply the transforms in the config. """ 35 | for selector, call in config.last('astTransforms', ()): 36 | for node in selector.walk(tree): 37 | call(node, config) 38 | -------------------------------------------------------------------------------- /java2python/compiler/block.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.compiler.block -> Visitors combined with templates. 4 | # 5 | # This module defines classes which combine AST walking with source 6 | # generation. We've put these two behaviors into separate modules, 7 | # java2python.compiler.template for creating source code, and 8 | # java2python.compiler.visitor for walking ANTLR trees. 9 | # 10 | # Each of the classes depends on the behavior of its counterpart. 11 | # This means they're very tightly coupled and that the classes are not 12 | # very reusable. The module split does allow for grouping of related 13 | # methods and does hide the cluttered code. 14 | 15 | from sys import modules 16 | from java2python.compiler import template, visitor 17 | 18 | 19 | def addTypeToModule((className, factoryName)): 20 | """ Constructs and adds a new type to this module. """ 21 | bases = (getattr(template, className), getattr(visitor, className)) 22 | newType = type(className, bases, dict(factoryName=factoryName)) 23 | setattr(modules[__name__], className, newType) 24 | 25 | 26 | map(addTypeToModule, ( 27 | ('Annotation', 'at'), 28 | ('Class', 'klass'), 29 | ('Comment', 'comment'), 30 | ('Enum', 'enum'), 31 | ('Expression', 'expr'), 32 | ('Interface', 'interface'), 33 | ('Method', 'method'), 34 | ('MethodContent', 'methodContent'), 35 | ('Module', 'module'), 36 | ('Statement', 'statement'), 37 | ) 38 | ) 39 | -------------------------------------------------------------------------------- /java2python/compiler/template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.compiler.template -> Base classes for writing Python source. 4 | # 5 | # This module defines templates -- chunks of Python source code -- 6 | # that can be easily manipulated and written. Each class provides 7 | # string methods (__str__, dump, dumps) for serializing instances as a 8 | # source code string. 9 | # 10 | # The Factory class is used to to provide runtime lookup of concrete 11 | # classes; this was necessary to accommodate splitting the behavior of 12 | # the compiler subpackage into multiple modules. So-called patterns 13 | # are usually a sign of a bad design and/or language limitations, and 14 | # this case is no exception. 15 | 16 | from cStringIO import StringIO 17 | from functools import partial 18 | from itertools import chain, ifilter, imap 19 | 20 | from java2python.lang import tokens 21 | from java2python.lib import FS, colors 22 | 23 | 24 | class Factory(object): 25 | """ Factory -> creates pre-configured callables for new block instances. 26 | 27 | Both templates and visitors use an instance of this class as a simple 28 | interface to create new blocks like this: 29 | 30 | stat = self.factory.statement() 31 | 32 | The `__getattr__` method does the work of looking up and returning 33 | the appropriate block class. The lookup depends on the types 34 | registry, which is populated by the FactoryTypeDetector metaclass 35 | below. 36 | 37 | One important thing to realize regarding this factory is this: 38 | when an attribute is requested (`self.factory.expr` for example), 39 | the factory locates the type and returns a constructor for it with 40 | the config object pre-applied. 41 | 42 | """ 43 | types = {} 44 | 45 | def __init__(self, config): 46 | self.config = config 47 | 48 | def __getattr__(self, name): 49 | try: 50 | return partial(self.types[name], self.config) 51 | except (KeyError, ): 52 | raise AttributeError('Factory missing "{0}" type.'.format(name)) 53 | 54 | 55 | class FactoryTypeDetector(type): 56 | """ FactoryTypeDetector -> detects factory-creatable types as they are defined. 57 | 58 | As subclasses are created they are checked for an attribute called 59 | `factoryName`. If present, that key is used to populate the 60 | type registry in the Factory class. 61 | 62 | Note that the actual subclasses are not created here (templates and 63 | visitors do not specify a `factoryName`). Actual factory types are created 64 | in `java2python.compiler.block`. This is because we're after not 65 | templates or visitors, but rather visitors combined with templates (aka 66 | blocks). Refer to the `blocks` module for the specific factory 67 | type names. 68 | 69 | """ 70 | def __init__(cls, name, bases, namespace): 71 | try: 72 | Factory.types[cls.factoryName] = cls 73 | except (AttributeError, ): 74 | pass 75 | 76 | 77 | class Base(object): 78 | """ Base -> base class for formatting Python output. 79 | 80 | This class defines a large set of attributes and methods for the 81 | other concrete templates defined below. The items defined here 82 | can be grouped as follows: 83 | 84 | * References 85 | 86 | This class defines `bases`, `children`, `decorators`, etc. for 87 | tracking the relationship between this instance and other blocks. 88 | 89 | * Type Information 90 | 91 | This class defines many is-A properties, such as isClass, 92 | isModule, isVoid, etc. Subclasses typically override one or more 93 | of these with an attribute or property. 94 | 95 | * Configuration 96 | 97 | This class provides utility methods for retrieving values from the 98 | runtime configuration. See the definition of `configHandler` and 99 | `configHandlers` for details. 100 | 101 | * Serialization 102 | 103 | This class provides a default implementation for subclasses to 104 | serialize their instances as Python source code strings. Notably, 105 | the `__str__` method is provided, which in turn defers most of its 106 | work to the `dumps` method. Subclasses provide different 107 | implementations of these methods where needed. 108 | 109 | Also, the `__repr__` method is defined by this class for printing 110 | a the template as tree for debugging. 111 | 112 | """ 113 | __metaclass__ = FactoryTypeDetector 114 | isAnnotation = isClass = isComment = isEnum = isExpression = \ 115 | isInterface = isMethod = isModule = isStatement = False 116 | 117 | def __init__(self, config, name=None, type=None, parent=None): 118 | self.bases = [] 119 | self.children = [] 120 | self.config = config 121 | self.decorators = [] 122 | self.overloaded = None 123 | self.factory = Factory(config) 124 | self.modifiers = [] 125 | self.name = name 126 | self.parameters = [] 127 | self.parent = parent 128 | self.type = type 129 | self.variables = [] 130 | if parent: 131 | parent.children.append(self) 132 | 133 | def __repr__(self): 134 | """ Returns the debug string representation of this template. """ 135 | name = colors.white('name:') + colors.cyan(self.name) if self.name else '' 136 | parts = [colors.green(self.typeName), name] 137 | if self.type: 138 | parts.append(colors.white('type:') + colors.cyan(self.type)) 139 | if self.modifiers: 140 | parts.append(colors.white('modifiers:') + colors.cyan(','.join(self.modifiers))) 141 | return ' '.join(parts) 142 | 143 | def __str__(self): 144 | """ Returns the Python source code representation of this template. """ 145 | handlers = self.configHandlers('Output') 146 | return reduce(lambda v, func:func(self, v), handlers, self.dumps(-1)) 147 | 148 | def adopt(self, child, index=-1): 149 | """ Adds child to this objecs children and sets the childs parent. """ 150 | self.children.insert(index, child) 151 | child.parent = self 152 | 153 | def altIdent(self, name): 154 | """ Returns an alternate identifier for the one given. """ 155 | for klass in self.parents(lambda v:v.isClass): 156 | if name in klass.variables: 157 | try: 158 | method = self.parents(lambda v:v.isMethod).next() 159 | except (StopIteration, ): 160 | return name 161 | if name in [p['name'] for p in method.parameters]: 162 | return name 163 | if name in method.variables: 164 | return name 165 | return ('cls' if method.isStatic else 'self') + '.' + name 166 | return name 167 | 168 | def configHandler(self, part, suffix='Handler', default=None): 169 | """ Returns the config handler for this type of template. """ 170 | name = '{0}{1}{2}'.format(self.typeName, part, suffix) 171 | return self.config.last(name, default) 172 | 173 | def configHandlers(self, part, suffix='Handlers'): 174 | """ Returns config handlers for this type of template """ 175 | name = '{0}{1}{2}'.format(self.typeName, part, suffix) 176 | return imap(self.toIter, chain(*self.config.every(name, []))) 177 | 178 | def dump(self, fd, level=0): 179 | """ Writes the Python source code for this template to the given file. """ 180 | indent, isNotNone = level * self.indent, lambda x:x is not None 181 | lineFormat = '{0}{1}\n'.format 182 | for line in ifilter(isNotNone, self.iterPrologue()): 183 | line = lineFormat(indent, line) 184 | fd.write(line if line.strip() else '\n') 185 | for item in ifilter(isNotNone, self.iterHead()): 186 | item.dump(fd, level+1) 187 | for item in self.iterBody(): 188 | item.dump(fd, level+1) 189 | for line in ifilter(isNotNone, self.iterEpilogue()): 190 | line = lineFormat(indent, line) 191 | fd.write(line if line.strip() else '\n') 192 | 193 | def dumps(self, level=0): 194 | """ Dumps this template to a string. """ 195 | fd = StringIO() 196 | self.dump(fd, level) 197 | return fd.getvalue() 198 | 199 | def dumpRepr(self, fd, level=0): 200 | """ Writes a debug string for this template to the given file. """ 201 | indent, default = self.indent, lambda x, y:None 202 | fd.write('{0}{1!r}\n'.format(indent*level, self)) 203 | for child in ifilter(None, self.children): 204 | getattr(child, 'dumpRepr', default)(fd, level+1) 205 | 206 | @property 207 | def indent(self): 208 | """ Returns the indent string for this item. """ 209 | return self.config.last('indentPrefix', ' ') 210 | 211 | @property 212 | def isPublic(self): 213 | """ True if this item is static. """ 214 | return 'public' in self.modifiers 215 | 216 | @property 217 | def isStatic(self): 218 | """ True if this item is static. """ 219 | return 'static' in self.modifiers 220 | 221 | @property 222 | def isVoid(self): 223 | """ True if this item is void. """ 224 | return 'void' == self.type 225 | 226 | def iterPrologue(self): 227 | """ Yields the items in the prologue of this template. """ 228 | return chain(*(h(self) for h in self.configHandlers('Prologue'))) 229 | 230 | def iterHead(self): 231 | """ Yields the items in the head of this template. """ 232 | items = chain(*(h(self) for h in self.configHandlers('Head'))) 233 | return imap(self.toExpr, items) 234 | 235 | def iterBody(self): 236 | """ Yields the items in the body of this template. """ 237 | return iter(self.children) 238 | 239 | def iterEpilogue(self): 240 | """ Yields the items in the epilogue of this template. """ 241 | return chain(*(h(self) for h in self.configHandlers('Epilogue'))) 242 | 243 | def makeParam(self, name, type, **kwds): 244 | """ Creates a parameter as a mapping. """ 245 | param = dict(name=name, type=type) 246 | if 'default' in kwds: 247 | param['default'] = kwds['default'] 248 | return param 249 | 250 | def parents(self, pred=lambda v:True): 251 | """ Yield each parent in the family tree. """ 252 | while self: 253 | if pred(self): 254 | yield self 255 | self = self.parent 256 | 257 | def find(self, pred=lambda v:True): 258 | """ Yield each child in the family tree. """ 259 | for child in self.children: 260 | if pred(child): 261 | yield child 262 | if hasattr(child, 'find'): 263 | for value in child.find(pred): 264 | yield value 265 | 266 | @property 267 | def className(self): 268 | """ Returns the name of the class of this item. """ 269 | return self.__class__.__name__ 270 | 271 | @property 272 | def typeName(self): 273 | """ Returns the name of this template type. """ 274 | return self.className.lower() 275 | 276 | def toExpr(self, value): 277 | """ Returns an expression for the given value if it is a string. """ 278 | try: 279 | return self.factory.expr(left=value+'') 280 | except (TypeError, ): 281 | return value 282 | 283 | def toIter(self, value): 284 | """ Returns an iterator for the given value if it is a string. """ 285 | try: 286 | value + '' 287 | except (TypeError, ): 288 | return value 289 | else: 290 | def wrapper(*a, **b): 291 | yield value 292 | return wrapper 293 | 294 | 295 | class Expression(Base): 296 | """ Expression -> formatting for Python expressions. """ 297 | 298 | isExpression = True 299 | 300 | def __init__(self, config, left='', right='', fs=FS.lr, parent=None, tail=''): 301 | super(Expression, self).__init__(config, parent=parent) 302 | self.left, self.right, self.fs, self.tail = left, right, fs, tail 303 | 304 | def __repr__(self): 305 | """ Returns the debug string representation of this template. """ 306 | parts, parent, showfs = [colors.blue(self.typeName)], self.parent, True 307 | if isinstance(self.left, (basestring, )) and self.left: 308 | parts.append(colors.white('left:') + colors.yellow(self.left)) 309 | showfs = False 310 | if isinstance(self.right, (basestring, )) and self.right: 311 | parts.append(colors.white('right:') + colors.yellow(self.right)) 312 | showfs = False 313 | if self.modifiers: 314 | parts.append(colors.white('modifiers:') + colors.cyan(','.join(self.modifiers))) 315 | if self.type: 316 | parts.append(colors.white('type:') + colors.cyan(self.type)) 317 | if showfs: 318 | parts.append(colors.white('format:') + colors.yellow(self.fs)) 319 | if self.tail: 320 | parts.append(colors.white('tail:') + colors.black(self.tail)) 321 | return ' '.join(parts) 322 | 323 | def __str__(self): 324 | """ Returns the Python source code representation of this template. """ 325 | return self.fs.format(left=self.left, right=self.right) + self.tail 326 | 327 | def dump(self, fd, level=0): 328 | """ Writes the Python source code for this template to the given file. """ 329 | line = '{0}{1}\n'.format(self.indent*level, self) 330 | fd.write(line if line.strip() else '\n') 331 | 332 | def dumpRepr(self, fd, level=0): 333 | """ Writes a debug string for this template to the given file. """ 334 | fd.write('{0}{1!r}\n'.format(self.indent*level, self)) 335 | for obj in (self.left, self.right): 336 | dumper = getattr(obj, 'dumpRepr', lambda x, y:None) 337 | dumper(fd, level+1) 338 | 339 | @property 340 | def isComment(self): 341 | """ True if this expression is a comment. """ 342 | try: 343 | return self.left.strip().startswith('#') 344 | except (AttributeError, ): 345 | return False 346 | 347 | 348 | class Comment(Expression): 349 | """ Comment -> formatting for Python comments. """ 350 | 351 | isComment = True 352 | 353 | def __repr__(self): 354 | """ Returns the debug string representation of this comment. """ 355 | parts = [colors.white(self.typeName+':'), 356 | colors.black(self.left) + colors.black(self.right) + colors.black(self.tail), ] 357 | return ' '.join(parts) 358 | 359 | 360 | 361 | class Statement(Base): 362 | """ Statement -> formatting for Python statements. """ 363 | 364 | isStatement = True 365 | 366 | def __init__(self, config, keyword, fs=FS.lr, parent=None): 367 | super(Statement, self).__init__(config, parent=parent) 368 | self.keyword = keyword 369 | self.expr = self.factory.expr(left=keyword, fs=fs) 370 | self.expr.parent = self 371 | 372 | def __repr__(self): 373 | """ Returns the debug string representation of this statement. """ 374 | parts = [colors.green(self.typeName), colors.white('keyword:')+colors.cyan(self.keyword)] 375 | return ' '.join(parts) 376 | 377 | def iterPrologue(self): 378 | """ Yields the keyword (and clause, if any) for this statement . """ 379 | yield self.expr 380 | 381 | 382 | class Module(Base): 383 | """ Module -> formatting for Python modules. """ 384 | isModule = True 385 | 386 | def iterBody(self): 387 | """ Yields the items in the body of this template. """ 388 | blank, prev = self.factory.expr(), None 389 | for child in super(Module, self).iterBody(): 390 | if prev and not prev.isComment: 391 | yield blank 392 | if prev and prev.isClass and child and child.isClass: 393 | yield blank 394 | yield child 395 | prev = child 396 | 397 | 398 | class ClassMethodSharedMixin(object): 399 | """ ClassMethodSharedMixin -> shared methods for Class and Method types. """ 400 | 401 | def iterPrologue(self): 402 | """ Yields the items in the prologue of this template. """ 403 | prologue = super(ClassMethodSharedMixin, self).iterPrologue() 404 | return chain(prologue, self.decorators, self.iterDecl()) 405 | 406 | 407 | class Class(ClassMethodSharedMixin, Base): 408 | """ Class -> formatting for Python classes. """ 409 | isClass = True 410 | 411 | def iterBases(self): 412 | """ Yields the base classes for this type. """ 413 | return chain(*(h(self) for h in self.configHandlers('Base'))) 414 | 415 | def iterDecl(self): 416 | """ Yields the declaration for this type. """ 417 | bases = ', '.join(self.iterBases()) 418 | bases = '({0})'.format(bases) if bases else '' 419 | yield 'class {0}{1}:'.format(self.name, bases) 420 | 421 | def iterBody(self): 422 | """ Yields the items in the body of this template. """ 423 | def sprinkleBlanks(body): 424 | blank, prev = self.factory.expr(), None 425 | for item in body: 426 | if prev: 427 | if type(prev) != type(item) and not prev.isComment: 428 | yield blank 429 | elif item.isMethod and prev.isMethod: 430 | yield blank 431 | elif prev.isClass: 432 | yield blank 433 | yield item 434 | prev = item 435 | for handler in self.configHandlers('PostWalk'): 436 | handler(self) 437 | head = any(self.iterHead()) 438 | body = list(super(Class, self).iterBody()) 439 | tail = () if (body or head) else [self.factory.expr(left='pass')] 440 | body = () if tail else sprinkleBlanks(body) 441 | return chain(body, tail) 442 | 443 | 444 | class Annotation(Class): 445 | """ Annotation -> formatting for annotations converted to Python classes. """ 446 | isAnnotation = True 447 | 448 | def __init__(self, config, name=None, type=None, parent=None): 449 | super(Annotation, self).__init__(config, name, type, parent) 450 | 451 | 452 | class Enum(Class): 453 | """ Enum -> formatting for enums converted to Python classes. """ 454 | isEnum = True 455 | 456 | 457 | class Interface(Class): 458 | """ Interface -> formatting for interfaces converted to Python classes. """ 459 | isInterface = True 460 | 461 | 462 | class MethodContent(Base): 463 | """ MethodContent -> formatting for content within Python methods. """ 464 | 465 | 466 | class Method(ClassMethodSharedMixin, Base): 467 | """ Method -> formatting for Python methods. """ 468 | isMethod = True 469 | 470 | def __init__(self, config, name=None, type=None, parent=None): 471 | super(Method, self).__init__(config, name, type, parent) 472 | self.parameters.append(self.makeParam('self', 'object')) 473 | 474 | def iterParams(self): 475 | """ Yields the parameters of this method template. """ 476 | return chain(*(h(self) for h in self.configHandlers('Param'))) 477 | 478 | def iterDecl(self): 479 | """ Yields the declaration for this method template. """ 480 | def formatParam(p): 481 | if 'default' in p: 482 | return '{0}={1}'.format(p['name'], p['default']) 483 | return p['name'] 484 | params = ', '.join(formatParam(param) for param in self.iterParams()) 485 | yield 'def {0}({1}):'.format(self.name, params) 486 | 487 | def iterBody(self): 488 | """ Yields the items in the body of this method template. """ 489 | head = any(self.iterHead()) 490 | body = list(super(Method, self).iterBody()) 491 | tail = () if (body or head) else [self.factory.expr(left='pass')] 492 | return chain(body, tail) 493 | -------------------------------------------------------------------------------- /java2python/config/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.config -> subpackage for run-time configuration. 4 | 5 | from functools import reduce 6 | from imp import load_source 7 | from os import path 8 | 9 | 10 | class Config(object): 11 | """ Config -> wraps multiple configuration modules. """ 12 | 13 | def __init__(self, names): 14 | self.configs = [self.load(name) for name in names] 15 | 16 | def every(self, key, default=None): 17 | """ Returns the value at the given key from each config module. """ 18 | return [getattr(config, key, default) for config in self.configs] 19 | 20 | def last(self, key, default=None): 21 | """ Returns the value at the key from the last config defining it. """ 22 | for config in reversed(self.configs): 23 | if hasattr(config, key): 24 | return getattr(config, key) 25 | return default 26 | 27 | @staticmethod 28 | def load(name): 29 | """ Imports and returns a module from dotted form or filename. """ 30 | if path.exists(name) and path.isfile(name): 31 | mod = load_source(str(hash(name)), name) 32 | else: 33 | mod = reduce(getattr, name.split('.')[1:], __import__(name)) 34 | return mod 35 | -------------------------------------------------------------------------------- /java2python/config/default.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # This is the default configuration file for java2python. Unless 5 | # explicity disabled with the '-n' or '--nodefaults' option, the j2py 6 | # script will import this module for runtime configuration. 7 | 8 | from java2python.mod import basic, transform 9 | from java2python.lang.selector import * 10 | 11 | 12 | # Leading indent character or characters. Four spaces are used 13 | # because that is the recommendation of PEP 8. 14 | indentPrefix = ' ' * 4 15 | 16 | 17 | # Prefix character or characters for comments. The hash+space is 18 | # recommended by PEP 8. 19 | commentPrefix = '# ' 20 | 21 | 22 | # These values are strings or generators that yield strings 23 | # for a module prologue. 24 | modulePrologueHandlers = [ 25 | basic.shebangLine, 26 | basic.simpleDocString, 27 | 'from __future__ import print_function', 28 | basic.maybeBsr, 29 | basic.maybeAbstractHelpers, 30 | basic.maybeSyncHelpers, 31 | ] 32 | 33 | 34 | # These generators yield lines for a module epilogue. 35 | moduleEpilogueHandlers = [ 36 | basic.scriptMainStanza, 37 | ] 38 | 39 | 40 | # These generators yield (possibly modified) source strings for a 41 | # module. The `basic.outputSubs` handler references the list of 42 | # regular expression substitutions near the end of this module. 43 | moduleOutputHandlers = [ 44 | basic.outputSubs, 45 | ] 46 | 47 | 48 | # These generators yield doc strings for a class. 49 | classHeadHandlers = [ 50 | basic.simpleDocString, 51 | ] 52 | 53 | methodParamHandlers = [ 54 | basic.defaultParams, 55 | ] 56 | 57 | # This is the name of the callable used to construct locks for an object with 58 | # the synchronized keyword. 59 | methodLockFunctionName = 'lock_for_object' 60 | 61 | classBaseHandlers = [ 62 | basic.defaultBases, 63 | ] 64 | 65 | interfaceBaseHandlers = [ 66 | basic.defaultBases, 67 | ] 68 | 69 | # These generators are called after a class has been completely 70 | # generated. The class content sorter sorts the methods of a class by 71 | # name. It's commented out because its output differs so greatly 72 | # from its input, and because it's really not very useful. 73 | classPostWalkHandlers = [ 74 | basic.moveStaticExpressions, 75 | ## basic.classContentSort, 76 | ] 77 | 78 | 79 | enumHeadHandlers = [ 80 | basic.simpleDocString, 81 | ] 82 | 83 | 84 | interfaceHeadHandlers = [ 85 | basic.simpleDocString, 86 | '__metaclass__ = ABCMeta', 87 | ] 88 | 89 | 90 | interfacePostWalkMutators = [ 91 | ] 92 | 93 | 94 | methodHeadHandlers = [ 95 | basic.simpleDocString, 96 | ] 97 | 98 | 99 | methodPrologueHandlers = [ 100 | basic.maybeAbstractMethod, 101 | basic.maybeClassMethod, 102 | basic.overloadedClassMethods, 103 | # NB: synchronized should come after classmethod 104 | basic.maybeSynchronizedMethod, 105 | ] 106 | 107 | 108 | # This handler creates enum values on enum classes after they've been 109 | # defined. The handler tries to match Java semantics by using 110 | # strings. Refer to the documentation for details. 111 | enumValueHandler = basic.enumConstStrings 112 | 113 | # Alternatively, you can use this handler to construct enum values as 114 | # integers. 115 | #enumValueHandler = basic.enumConstInts 116 | 117 | 118 | # When the compiler needs to make up a variable name (for example, to 119 | # emulate assignment expressions), it calls this handler to produce a 120 | # new one. 121 | expressionVariableNamingHandler = basic.globalNameCounter 122 | 123 | 124 | # This handler simply creates comments in the file for package 125 | # declarations. 126 | modulePackageDeclarationHandler = basic.commentedPackages 127 | 128 | 129 | # This handler can be used instead to create __init__.py files for 130 | # 'namespace packages' via pkgutil. 131 | # modulePackageDeclarationHandler = basic.namespacePackages 132 | 133 | 134 | # This handler is turns java imports into python imports. No mapping 135 | # of packages is performed: 136 | # moduleImportDeclarationHandler = basic.simpleImports 137 | 138 | # This import decl. handler can be used instead to produce comments 139 | # instead of import statements: 140 | # moduleImportDeclarationHandler = basic.commentedImports 141 | 142 | # The AST transformation function uses these declarations to modify an 143 | # AST before compiling it to python source. Having these declarations 144 | # in a config file gives clients an opportunity to change the 145 | # transformation behavior. 146 | 147 | astTransforms = [ 148 | (Type('NULL'), transform.null2None), 149 | (Type('FALSE'), transform.false2False), 150 | (Type('TRUE'), transform.true2True), 151 | (Type('IDENT'), transform.keywordSafeIdent), 152 | 153 | (Type('DECIMAL_LITERAL'), transform.syntaxSafeDecimalLiteral), 154 | (Type('FLOATING_POINT_LITERAL'), transform.syntaxSafeFloatLiteral), 155 | 156 | (Type('TYPE') > Type('BOOLEAN'), transform.typeSub), 157 | (Type('TYPE') > Type('BYTE'), transform.typeSub), 158 | (Type('TYPE') > Type('CHAR'), transform.typeSub), 159 | (Type('TYPE') > Type('FLOAT'), transform.typeSub), 160 | (Type('TYPE') > Type('INT'), transform.typeSub), 161 | (Type('TYPE') > Type('SHORT'), transform.typeSub), 162 | (Type('TYPE') > Type('LONG'), transform.typeSub), 163 | (Type('TYPE') > Type('DOUBLE'), transform.typeSub), 164 | 165 | (Type('METHOD_CALL') > Type('DOT') > Type('IDENT', 'length'), 166 | transform.lengthToLen), 167 | 168 | (Type('METHOD_CALL') > Type('DOT') > ( 169 | Type('IDENT', 'String') + 170 | Type('IDENT', 'format') 171 | ), 172 | transform.formatString), 173 | 174 | (Type('TYPE') > Type('QUALIFIED_TYPE_IDENT') > Type('IDENT'), 175 | transform.typeSub), 176 | 177 | ] 178 | 179 | 180 | # not implemented: 181 | 182 | # minimum parameter count to trigger indentation of parameter names 183 | # in method declarations. set to 0 to disable. 184 | #minIndentParams = 5 185 | 186 | # Specifies handler for cast operations of non-primitive types are handled 187 | # (primitive types are automatically handled). Use basic.castDrop to leave 188 | # cast expressions out of generated source. Use basic.castCtor to transform 189 | # casts into constructor calls. Or you can specify a function of your own. 190 | expressionCastHandler = basic.castDrop 191 | 192 | 193 | # Values below are used by the handlers. They're here for 194 | # convenience. 195 | 196 | 197 | # module output subs. 198 | moduleOutputSubs = [ 199 | (r'System\.out\.println\((.*)\)', r'print(\1)'), 200 | (r'System\.out\.print_\((.*?)\)', r'print(\1, end="")'), 201 | (r'(.*?)\.equals\((.*?)\)', r'\1 == \2'), 202 | (r'(.*?)\.equalsIgnoreCase\((.*?)\)', r'\1.lower() == \2.lower()'), 203 | (r'([\w.]+)\.size\(\)', r'len(\1)'), 204 | #(r'(\w+)\.get\((.*?)\)', r'\1[\2]'), 205 | (r'(\s)(\S*?)(\.toString\(\))', r'\1\2.__str__()'), 206 | (r'(\s)def toString', r'\1def __str__'), 207 | (r'(\s)(\S*?)(\.toLowerCase\(\))', r'\1\2.lower()'), 208 | (r'(.*?)IndexOutOfBoundsException\((.*?)\)', r'\1IndexError(\2)'), 209 | (r'\.__class__\.getName\(\)', '.__class__.__name__'), 210 | (r'\.getClass\(\)', '.__class__'), 211 | (r'\.getName\(\)', '.__name__'), 212 | (r'\.getInterfaces\(\)', '.__bases__'), 213 | (r'String\.valueOf\((.*?)\)', r'str(\1)'), 214 | #(r'(\s)(\S*?)(\.toString\(\))', r'\1str(\2)'), 215 | (r'Math\.', ''), 216 | ] 217 | 218 | 219 | typeSubs = { 220 | 'Boolean' : 'bool', 221 | 'boolean' : 'bool', 222 | 223 | 'Byte' : 'int', 224 | 'byte' : 'int', 225 | 226 | 'Char' : 'str', 227 | 'char' : 'str', 228 | 229 | 'Integer' : 'int', 230 | 'int' : 'int', 231 | 232 | 'Short' : 'int', 233 | 'short' : 'int', 234 | 235 | 'Long' : 'long', 236 | 'long' : 'long', 237 | 238 | 'Float' : 'float', 239 | 'float' : 'float', 240 | 241 | 'Double' : 'float', 242 | 'double' : 'float', 243 | 244 | 'String' : 'str', 245 | 'java.lang.String' : 'str', 246 | 247 | 'Object' : 'object', 248 | 249 | 'IndexOutOfBoundsException' : 'IndexError', 250 | 'IOException': 'IOError', 251 | } 252 | -------------------------------------------------------------------------------- /java2python/lang/Java.tokens: -------------------------------------------------------------------------------- 1 | PACKAGE=84 2 | EXPONENT=173 3 | STAR=49 4 | WHILE=103 5 | MOD=32 6 | MOD_ASSIGN=33 7 | CASE=58 8 | CHAR=60 9 | NEW=82 10 | DO=64 11 | GENERIC_TYPE_PARAM_LIST=138 12 | CLASS_INSTANCE_INITIALIZER=121 13 | ARRAY_ELEMENT_ACCESS=115 14 | FOR_CONDITION=129 15 | NOT=34 16 | VAR_DECLARATION=160 17 | ANNOTATION_METHOD_DECL=109 18 | DIV_ASSIGN=14 19 | LOGICAL_AND=26 20 | BREAK=56 21 | UNARY_PLUS=159 22 | BIT_SHIFT_RIGHT_ASSIGN=9 23 | TYPE=157 24 | RPAREN=43 25 | INC=21 26 | FINAL=70 27 | IMPORT=78 28 | STRING_LITERAL=170 29 | FOR_UPDATE=132 30 | FLOATING_POINT_LITERAL=168 31 | CAST_EXPR=118 32 | NOT_EQUAL=35 33 | VOID_METHOD_DECL=163 34 | THIS=95 35 | RETURN=88 36 | DOUBLE=65 37 | ENUM_TOP_LEVEL_SCOPE=125 38 | VOID=101 39 | SUPER=92 40 | COMMENT=181 41 | ANNOTATION_INIT_KEY_LIST=107 42 | JAVA_ID_START=178 43 | FLOAT_TYPE_SUFFIX=174 44 | PRE_DEC=149 45 | RBRACK=41 46 | IMPLEMENTS_CLAUSE=140 47 | SWITCH_BLOCK_LABEL_LIST=154 48 | LINE_COMMENT=182 49 | PRIVATE=85 50 | STATIC=90 51 | BLOCK_SCOPE=117 52 | ANNOTATION_INIT_DEFAULT_KEY=106 53 | SWITCH=93 54 | NULL=83 55 | VAR_DECLARATOR=161 56 | MINUS_ASSIGN=31 57 | ELSE=66 58 | STRICTFP=91 59 | CHARACTER_LITERAL=169 60 | PRE_INC=150 61 | ANNOTATION_LIST=108 62 | ELLIPSIS=17 63 | NATIVE=81 64 | OCTAL_ESCAPE=177 65 | UNARY_MINUS=158 66 | THROWS=97 67 | LCURLY=23 68 | INT=79 69 | FORMAL_PARAM_VARARG_DECL=135 70 | METHOD_CALL=144 71 | ASSERT=54 72 | TRY=100 73 | INTERFACE_TOP_LEVEL_SCOPE=139 74 | SHIFT_LEFT=45 75 | WS=180 76 | SHIFT_RIGHT=47 77 | FORMAL_PARAM_STD_DECL=134 78 | LOCAL_MODIFIER_LIST=142 79 | OR=36 80 | LESS_THAN=25 81 | SHIFT_RIGHT_ASSIGN=48 82 | EXTENDS_BOUND_LIST=127 83 | JAVA_SOURCE=143 84 | CATCH=59 85 | FALSE=69 86 | INTEGER_TYPE_SUFFIX=172 87 | DECIMAL_LITERAL=167 88 | THROW=96 89 | FOR_INIT=131 90 | DEC=12 91 | PROTECTED=86 92 | CLASS=61 93 | LBRACK=22 94 | BIT_SHIFT_RIGHT=8 95 | THROWS_CLAUSE=156 96 | GREATER_OR_EQUAL=19 97 | FOR=73 98 | THIS_CONSTRUCTOR_CALL=155 99 | LOGICAL_NOT=27 100 | JAVADOC_COMMENT=183 101 | FLOAT=72 102 | ABSTRACT=53 103 | AND=4 104 | POST_DEC=147 105 | AND_ASSIGN=5 106 | STATIC_ARRAY_CREATOR=152 107 | MODIFIER_LIST=145 108 | ANNOTATION_SCOPE=110 109 | LPAREN=29 110 | IF=74 111 | AT=7 112 | ESCAPE_SEQUENCE=175 113 | CONSTRUCTOR_DECL=124 114 | LABELED_STATEMENT=141 115 | UNICODE_ESCAPE=176 116 | EXPR=126 117 | SYNCHRONIZED=94 118 | BOOLEAN=55 119 | CLASS_TOP_LEVEL_SCOPE=123 120 | IMPLEMENTS=75 121 | CONTINUE=62 122 | COMMA=11 123 | TRANSIENT=98 124 | EQUAL=18 125 | XOR_ASSIGN=52 126 | LOGICAL_OR=28 127 | IDENT=164 128 | QUALIFIED_TYPE_IDENT=151 129 | ARGUMENT_LIST=112 130 | PLUS=38 131 | HEX_LITERAL=165 132 | ANNOTATION_INIT_BLOCK=105 133 | DOT=15 134 | SHIFT_LEFT_ASSIGN=46 135 | FORMAL_PARAM_LIST=133 136 | GENERIC_TYPE_ARG_LIST=137 137 | ANNOTATION_TOP_LEVEL_SCOPE=111 138 | DOTSTAR=16 139 | BYTE=57 140 | XOR=51 141 | JAVA_ID_PART=179 142 | GREATER_THAN=20 143 | VOLATILE=102 144 | PARENTESIZED_EXPR=146 145 | CLASS_STATIC_INITIALIZER=122 146 | ARRAY_DECLARATOR_LIST=114 147 | LESS_OR_EQUAL=24 148 | DEFAULT=63 149 | OCTAL_LITERAL=166 150 | HEX_DIGIT=171 151 | SHORT=89 152 | INSTANCEOF=76 153 | MINUS=30 154 | EXTENDS_CLAUSE=128 155 | TRUE=99 156 | SEMI=44 157 | STAR_ASSIGN=50 158 | VAR_DECLARATOR_LIST=162 159 | ARRAY_DECLARATOR=113 160 | COLON=10 161 | OR_ASSIGN=37 162 | ENUM=67 163 | QUESTION=40 164 | FINALLY=71 165 | RCURLY=42 166 | PLUS_ASSIGN=39 167 | ASSIGN=6 168 | ANNOTATION_INIT_ARRAY_ELEMENT=104 169 | FUNCTION_METHOD_DECL=136 170 | INTERFACE=77 171 | POST_INC=148 172 | DIV=13 173 | CLASS_CONSTRUCTOR_CALL=120 174 | LONG=80 175 | FOR_EACH=130 176 | EXTENDS=68 177 | PUBLIC=87 178 | ARRAY_INITIALIZER=116 179 | CATCH_CLAUSE_LIST=119 180 | SUPER_CONSTRUCTOR_CALL=153 181 | '>='=19 182 | '=='=18 183 | 'implements'=75 184 | 'this'=95 185 | 'volatile'=102 186 | ';'=44 187 | 'return'=88 188 | 'for'=73 189 | 'protected'=86 190 | '^'=51 191 | '>>'=47 192 | 'static'=90 193 | 'catch'=59 194 | 'extends'=68 195 | '{'=23 196 | 'package'=84 197 | 'try'=100 198 | '&='=5 199 | '('=29 200 | ':'=10 201 | 'synchronized'=94 202 | 'default'=63 203 | 'public'=87 204 | '<<='=46 205 | ']'=41 206 | '>>>'=8 207 | 'enum'=67 208 | 'transient'=98 209 | 'assert'=54 210 | 'finally'=71 211 | 'new'=82 212 | '|='=37 213 | 'throws'=97 214 | '.*'=16 215 | '='=6 216 | '%'=32 217 | 'super'=92 218 | 'case'=58 219 | 'boolean'=55 220 | '<<'=45 221 | '<='=24 222 | '!='=35 223 | 'continue'=62 224 | '--'=12 225 | '<'=25 226 | '['=22 227 | '&'=4 228 | 'instanceof'=76 229 | '~'=34 230 | '/'=13 231 | '/='=14 232 | 'switch'=93 233 | '%='=33 234 | '>'=20 235 | '||'=28 236 | '&&'=26 237 | '+'=38 238 | '.'=15 239 | 'byte'=57 240 | 'import'=78 241 | '++'=21 242 | 'true'=99 243 | 'else'=66 244 | 'final'=70 245 | '^='=52 246 | '+='=39 247 | 'native'=81 248 | 'break'=56 249 | '...'=17 250 | '>>='=48 251 | 'void'=101 252 | '>>>='=9 253 | '?'=40 254 | 'private'=85 255 | 'int'=79 256 | 'if'=74 257 | 'while'=103 258 | '-'=30 259 | ','=11 260 | '-='=31 261 | 'short'=89 262 | 'long'=80 263 | '!'=27 264 | '|'=36 265 | 'class'=61 266 | 'null'=83 267 | '@'=7 268 | 'throw'=96 269 | ')'=43 270 | '*='=50 271 | 'do'=64 272 | 'char'=60 273 | 'strictfp'=91 274 | 'float'=72 275 | '}'=42 276 | 'abstract'=53 277 | 'double'=65 278 | 'false'=69 279 | '*'=49 280 | 'interface'=77 281 | -------------------------------------------------------------------------------- /java2python/lang/JavaDoc.g: -------------------------------------------------------------------------------- 1 | /* 2 | * Javadoc.g 3 | * Copyright (c) 2007 David Holroyd 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | grammar JavaDoc; 19 | 20 | 21 | options { 22 | k=3; 23 | output=AST; 24 | language=Python; 25 | ASTLabelType=CommonTree; 26 | } 27 | 28 | 29 | tokens { 30 | JAVADOC; 31 | INLINE_TAG; 32 | DESCRIPTION; 33 | PARA_TAG; 34 | TEXT_LINE; 35 | } 36 | 37 | 38 | commentBody 39 | : d=description paragraphTag* EOF 40 | -> ^(JAVADOC description paragraphTag*) 41 | ; 42 | 43 | 44 | description 45 | : textLine* 46 | -> ^(DESCRIPTION textLine*) 47 | ; 48 | 49 | 50 | textLine 51 | : textLineStart textLineContent* (NL | EOF!) 52 | | NL 53 | ; 54 | 55 | 56 | textLineStart 57 | : (LBRACE ATWORD)=> inlineTag 58 | | WORD | STARS | WS | LBRACE | RBRACE | AT 59 | ; 60 | 61 | 62 | textLineContent 63 | : (LBRACE ATWORD)=> inlineTag 64 | | WORD | STARS | WS | LBRACE | RBRACE | AT | ATWORD 65 | ; 66 | 67 | 68 | inlineTag 69 | : LBRACE ATWORD inlineTagContent* RBRACE 70 | -> ^(INLINE_TAG ATWORD inlineTagContent*) 71 | ; 72 | 73 | 74 | inlineTagContent 75 | : WORD | STARS | WS | AT | NL 76 | ; 77 | 78 | 79 | paragraphTag 80 | : ATWORD paragraphTagTail 81 | -> ^(PARA_TAG ATWORD paragraphTagTail) 82 | ; 83 | 84 | 85 | paragraphTagTail 86 | : textLineContent* (NL textLine* | EOF) 87 | -> textLineContent* NL? textLine* 88 | ; 89 | 90 | 91 | STARS 92 | : '*'+ 93 | ; 94 | 95 | 96 | LBRACE 97 | : '{' 98 | ; 99 | 100 | 101 | RBRACE 102 | : '}' 103 | ; 104 | 105 | 106 | AT 107 | : '@' 108 | ; 109 | 110 | 111 | WS 112 | : (' ' | '\t')+ 113 | ; 114 | 115 | 116 | NL options {k=*;} 117 | : ('\r\n' | '\r' | '\n') WS? (STARS WS?)? 118 | ; 119 | 120 | 121 | ATWORD 122 | : '@' WORD WORD_TAIL 123 | ; 124 | 125 | 126 | WORD 127 | : ~('\n' | ' ' | '\r' | '\t' | '{' | '}' | '@') WORD_TAIL 128 | ; 129 | 130 | 131 | fragment WORD_TAIL 132 | : (~('\n' | ' ' | '\r' | '\t' | '{' | '}'))* 133 | ; 134 | -------------------------------------------------------------------------------- /java2python/lang/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | .SILENT: clean 3 | 4 | all: JavaParser.py JavaLexer.py 5 | 6 | 7 | JavaParser.py: Java.g 8 | antlr3 Java.g 9 | 10 | 11 | JavaLexer.py: Java.g 12 | antlr3 Java.g 13 | 14 | 15 | clean: 16 | rm -f *.pyo 17 | rm -f *.pyc 18 | rm -f *Parser.py 19 | rm -f *Lexer.py 20 | rm -f *.tokens 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /java2python/lang/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.lang -> package marker 4 | # 5 | # Clients should import values from this module instead of our submodules. 6 | 7 | from java2python.lang.JavaLexer import JavaLexer as Lexer 8 | from java2python.lang.JavaParser import JavaParser as Parser 9 | from java2python.lang.base import StringStream, TokenStream, TreeAdaptor, tokens 10 | -------------------------------------------------------------------------------- /java2python/lang/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.lang.base -> lexer and parser support classes. 4 | # 5 | # This module provides the following: 6 | # 7 | # * `Tokens` 8 | # 9 | # This class is used to create the single `token` instance in this 10 | # module. It is used to map between parser tokens and their ids and 11 | # vice-versa. 12 | # 13 | # * `TreeAdaptor` 14 | # 15 | # This class is used by `java2python.compiler.tool`, where the 16 | # `buildAST` function associates an instance of it to a parser. The 17 | # `TreeAdaptor` class creates `LocalTree` instances. 18 | # 19 | # * `LocalTree` 20 | # 21 | # This class provides a slew of extra utility methods that are useful 22 | # when inspecting and printing tree nodes. 23 | # 24 | 25 | 26 | # ANTLR notes: 27 | # 28 | # recognizers: lexer, parser, treeparser 29 | # streams: string, file name, file handle 30 | # 31 | # Parsers use TokenStreams (CommonTokenStream or TokenRewriteStream) 32 | # 33 | # Tree parsers use TreeNodeStream (CommonTreeNodeStream) 34 | # 35 | # Lexers emit Token objects (buffered in TokenStream objects) 36 | # 37 | # Parsers build trees if their output is AST. 38 | # 39 | # token types: CommonToken and ClassicToken. Our tree adaptor 40 | # creates LocalTree instances instead. 41 | # 42 | # Tree (CommonTree) wraps Token objects. We provide extra functionality via 43 | # the LocalTree class. 44 | # 45 | # TreeAdaptor (CommonTreeAdaptor) is used by the parser to create 46 | # Tree objects. Our adaptor, TreeAdaptor, creates the LocalTree 47 | # instances. 48 | # 49 | 50 | from cStringIO import StringIO 51 | 52 | from antlr3 import ANTLRStringStream as StringStream, CommonTokenStream as TokenStream 53 | from antlr3.tree import CommonTreeAdaptor, CommonTree 54 | 55 | from java2python.lib import colors 56 | 57 | 58 | class Tokens(object): 59 | """ Tokens -> simplifies token id-name and name-id mapping. """ 60 | 61 | def __init__(self): 62 | self.cache, self.parserModule = {}, None 63 | 64 | def __getattr__(self, name): 65 | """ tokenname -> tokenvalue """ 66 | return getattr(self.module, name) 67 | 68 | @property 69 | def commentTypes(self): 70 | """ Well-known comment types. """ 71 | mod = self.module 72 | return (mod.COMMENT, mod.LINE_COMMENT, mod.JAVADOC_COMMENT, ) 73 | 74 | @property 75 | def map(self): 76 | """ (tokentype, tokenname) mapping as a dictionary """ 77 | cache, module = self.cache, self.module 78 | if cache: 79 | return cache 80 | mapping = [(getattr(module, k, None), k) for k in module.tokenNames] 81 | mapping = [(k, v) for k, v in mapping if k is not None] 82 | cache.update(mapping) 83 | return cache 84 | 85 | @property 86 | def methodTypes(self): 87 | """ Well-known method types. """ 88 | mod = self.module 89 | return (mod.VOID_METHOD_DECL, mod.FUNCTION_METHOD_DECL, ) 90 | 91 | @property 92 | def primitiveTypeNames(self): 93 | """ Type name of well-known primitive types """ 94 | return ('bool', 'str', 'int', 'long', 'float', ) 95 | 96 | @property 97 | def module(self): 98 | """ Provides lazy import to the parser module. """ 99 | module = self.parserModule 100 | if module: 101 | return module 102 | import java2python.lang.JavaParser as module 103 | self.parserModule = module 104 | return module 105 | 106 | @staticmethod 107 | def title(name): 108 | """ Returns a nice title given a token type name. """ 109 | return ''.join(part.title() for part in name.split('_')) 110 | 111 | 112 | ## sometimes you really do only need one. 113 | tokens = Tokens() 114 | 115 | 116 | class TreeAdaptor(CommonTreeAdaptor): 117 | """ TreeAdaptor -> defered tree node creator (for parsers). """ 118 | 119 | def __init__(self, lexer, parser): 120 | # CommonTreeAdaptor doesn't need to be __init__'ed 121 | self.lexer, self.parser = lexer, parser 122 | 123 | def createWithPayload(self, payload): 124 | """ Returns a new tree for the calling parser. """ 125 | return LocalTree(payload, self.lexer, self.parser) 126 | 127 | 128 | class LocalTree(CommonTree): 129 | """ LocalTree -> like CommonTree, but with more stuff. """ 130 | colorTypeMap = { 131 | 'CLASS' : colors.green, 132 | 'JAVA_SOURCE' : colors.green, 133 | 'VOID_METHOD_DECL' : colors.green, 134 | 'IDENT' : colors.yellow, 135 | 'TYPE' : colors.magenta, 136 | 'EXPR' : colors.blue, 137 | 'TRUE' : colors.yellow, 138 | 'FALSE' : colors.yellow, 139 | 'NULL' : colors.yellow, 140 | } 141 | 142 | def __init__(self, payload, lexer=None, parser=None): 143 | super(LocalTree, self).__init__(payload) 144 | self.lexer, self.parser = lexer, parser 145 | 146 | def childrenOfType(self, type): 147 | """ Returns a generator yielding children of this tree of the given type. """ 148 | return (c for c in self.children if c.type==type) 149 | 150 | def colorType(self, tokenType): 151 | """ Returns a color suitable for the given token type. """ 152 | return self.colorTypeMap.get(tokenType, colors.white)(tokenType) 153 | 154 | def colorText(self, tokenType, tokenText): 155 | """ Returns a colorized string from the given token type and text. """ 156 | return self.colorTypeMap.get(tokenType, colors.white)(tokenText) 157 | 158 | def colorComments(self, token): 159 | """ Formats, colors, and returns the comment text from the given token. """ 160 | ttyp = tokens.map.get(token.type) 161 | text = token.text.replace('\n', '\\n').replace('\r', '\\r').replace('\t', '\\t') 162 | item = '{0} [{1}:{2}] {3}'.format(ttyp, token.start, token.stop, text) 163 | yield colors.black(item) 164 | 165 | def dump(self, fd, level=0): 166 | """ Writes a debug representation of this tree to the given file. """ 167 | extras = lambda x, y:x and (x != y) 168 | seen, nform = set(), '{0}{1}{2}{3}' 169 | def innerDump(root, offset): 170 | token, indent = root.token, ' ' * offset 171 | start, stop = root.tokenStartIndex, root.tokenStopIndex 172 | idxes, ttyp = '', tokens.map.get(token.type, '?') 173 | line = token.line 174 | if start and stop and start == stop: 175 | idxes = 'start={}'.format(start) 176 | elif start and stop: 177 | idxes = 'start={}, stop={}'.format(start, stop) 178 | if line: 179 | idxes = 'line={}{}{}'.format(line, ', ' if idxes else '', idxes) 180 | idxes = ' [{}]'.format(idxes) if idxes else '' 181 | idxes = colors.black(idxes) 182 | args = [indent, self.colorType(ttyp), '', idxes, ''] 183 | if extras(token.text, ttyp): 184 | args[2] = ' ' + self.colorText(ttyp, token.text) 185 | for com in self.selectComments(start, seen): 186 | for line in self.colorComments(com): 187 | print >> fd, '{0}{1}'.format(indent, line) 188 | print >> fd, nform.format(*args) 189 | for child in root.getChildren(): 190 | innerDump(child, offset+1) 191 | for com in self.selectComments(root.tokenStopIndex, seen): 192 | for line in self.colorComments(com): 193 | print >> fd, '{0}{1}'.format(indent, line) 194 | innerDump(self, level) 195 | 196 | def dumps(self, level=0): 197 | """ Dump this token to a string. """ 198 | fd = StringIO() 199 | self.dump(fd, level) 200 | return fd.getvalue() 201 | 202 | def dupNode(self): 203 | """ Called by the parser to create a duplicate of this tree. """ 204 | get = lambda v:getattr(self, v, None) 205 | return LocalTree(self, get('lexer'), get('parser')) 206 | 207 | def findChildren(self, pred=lambda c:True): 208 | """ Depth-first search that yields nodes meeting the predicate. """ 209 | for child in self.children: 210 | if pred(child): 211 | yield child 212 | for sub in child.findChildren(pred): 213 | yield sub 214 | 215 | def findChildrenOfType(self, type): 216 | """ Depth-first search that yields nodes of the given type. """ 217 | return self.findChildren(lambda c:c.type==type) 218 | 219 | def firstChild(self, default=None): 220 | """ Returns the first child of this tree or the default. """ 221 | try: 222 | return self.children[0] 223 | except (IndexError, ): 224 | return default 225 | 226 | def firstChildOfType(self, type, default=None): 227 | """ Returns the first child of this tree that matches the given type. """ 228 | for child in self.children: 229 | if child.type == type: 230 | return child 231 | return default 232 | 233 | @property 234 | def isJavaSource(self): 235 | """ True if this tree is the outer most type. """ 236 | return self.token.type == tokens.JAVA_SOURCE 237 | 238 | @property 239 | def parentType(self): 240 | """ Returns the type of the parent tree. """ 241 | return self.parent.type 242 | 243 | def parents(self, pred=lambda v:True): 244 | """ Yield each parent in the family tree. """ 245 | while self: 246 | if pred(self): 247 | yield self 248 | self = self.parent 249 | 250 | @property 251 | def parserTokens(self): 252 | """ Returns the sequence of tokens used to create this tree. """ 253 | return self.parser.input.tokens[self.tokenStartIndex:self.tokenStopIndex] 254 | 255 | def selectComments(self, stop, memo): 256 | """ Returns the comment tokens for this tree up to the given index. """ 257 | pred = lambda k:k.type in tokens.commentTypes and k.index not in memo 258 | ctoks = [t for t in self.parser.input.tokens[0:stop] if pred(t)] 259 | memo.update(t.index for t in ctoks) 260 | return ctoks 261 | 262 | @property 263 | def withinExpr(self): 264 | """ True if this tree is contained within an expression. """ 265 | self = getattr(self.parent, 'parent', None) # skip first expr 266 | while self: 267 | if self.type in (tokens.EXPR, ): 268 | return True 269 | self = self.parent 270 | -------------------------------------------------------------------------------- /java2python/lang/selector.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.lang.selector -> declarative AST node selection 4 | # 5 | # This module provides classes for simple AST node selection that can be 6 | # easily combined to form complex, declarative rules for retrieving AST 7 | # nodes. 8 | # 9 | # The classes are similar to CSS selectors, with a nod to Python parsing 10 | # libraries like LEPL and PyParsing. At the moment, only a few very 11 | # basic selector types are implemented, but those that are here already 12 | # provide all of the functionality necessary for use within the package. 13 | # 14 | # Projects using java2python should regard this subpackage as 15 | # experimental. While the interfaces are not expected to change, the 16 | # semantics may. Use with caution. 17 | 18 | from java2python.lang import tokens 19 | 20 | 21 | class Selector(object): 22 | """ Base class for concrete selectors; provides operator methods. """ 23 | 24 | def __add__(self, other): 25 | """ E + F 26 | 27 | Like CSS "E + F": an F element immediately preceded by an E element 28 | """ 29 | return AdjacentSibling(self, other) 30 | 31 | def __and__(self, other): 32 | """ E & F 33 | 34 | Like CSS "E F": an F element descendant of an E element 35 | """ 36 | return Descendant(self, other) 37 | 38 | def __call__(self, *args, **kwds): 39 | """ Subclasses must implement. """ 40 | raise NotImplementedError('Selector class cannot be called.') 41 | 42 | def __getitem__(self, key): 43 | """ E[n] 44 | 45 | Like CSS "E:nth-child(n)": an E element, the n-th child of its parent 46 | """ 47 | return Nth(self, key) 48 | 49 | def __gt__(self, other): 50 | """ E > F 51 | 52 | Like CSS: "E > F": an F element child of an E element 53 | """ 54 | return Child(self, other) 55 | 56 | def __div__(self, other): 57 | """ E / F 58 | 59 | Produces a AnySibling. 60 | """ 61 | return AnySibling(self, other) 62 | 63 | def walk(self, tree): 64 | """ Select items from the tree and from the tree children. """ 65 | for item in self(tree): 66 | yield item 67 | for child in tree.children: 68 | for item in self.walk(child): 69 | yield item 70 | 71 | 72 | class Token(Selector): 73 | """ Token(...) -> select tokens by matching attributes. 74 | 75 | Token is the most generic and flexible Selector; using it, 76 | arbitrary nodes of any type, line number, position, and/or text 77 | can be selected. 78 | 79 | Calling Token() without any keywords is equivalent to: 80 | 81 | Token(channel=None, index=None, input=None, line=None, 82 | start=None, stop=None, text=None, type=None) 83 | 84 | Note that the value of each keyword can be a constant or a 85 | callable. When callables are specified, they are passed a the 86 | token and should return a bool. 87 | """ 88 | 89 | def __init__(self, **attrs): 90 | self.attrs = attrs 91 | ## we support strings so that the client can refer to the 92 | ## token name that way instead of via lookup or worse, integer. 93 | if isinstance(attrs.get('type'), (basestring, )): 94 | self.attrs['type'] = getattr(tokens, attrs.get('type')) 95 | 96 | def __call__(self, tree): 97 | items = self.attrs.items() 98 | token = tree.token 99 | 100 | def match_or_call(k, v): 101 | if callable(v): 102 | return v(token) 103 | return getattr(token, k)==v 104 | 105 | if all(match_or_call(k, v) for k, v in items if v is not None): 106 | yield tree 107 | 108 | def __str__(self): 109 | items = self.attrs.items() 110 | keys = ('{}={}'.format(k, v) for k, v in items if v is not None) 111 | return 'Token({})'.format(', '.join(keys)) 112 | 113 | 114 | class Nth(Selector): 115 | """ E[n] -> match any slice n of E 116 | 117 | Similar to the :nth-child pseudo selector in CSS, but without the 118 | support for keywords like 'odd', 'even', etc. 119 | """ 120 | def __init__(self, e, key): 121 | self.e, self.key = e, key 122 | 123 | def __call__(self, tree): 124 | for etree in self.e(tree): 125 | try: 126 | matches = tree.children[self.key] 127 | except (IndexError, ): 128 | return 129 | if not isinstance(matches, (list, )): 130 | matches = [matches] 131 | for child in matches: 132 | yield child 133 | 134 | def __str__(self): 135 | return 'Nth({0})[{1}]'.format(self.e, self.key) 136 | 137 | 138 | class Child(Selector): 139 | """ E > F select any F that is a child of E """ 140 | 141 | def __init__(self, e, f): 142 | self.e, self.f = e, f 143 | 144 | def __call__(self, tree): 145 | for ftree in self.f(tree): 146 | for etree in self.e(tree.parent): 147 | yield ftree 148 | 149 | def __str__(self): 150 | return 'Child({0} > {1})'.format(self.e, self.f) 151 | 152 | 153 | class Type(Selector): 154 | """ Type(T) select any token of type T 155 | 156 | Similar to the type selector in CSS. 157 | """ 158 | def __init__(self, key, value=None): 159 | self.key = key if isinstance(key, int) else getattr(tokens, key) 160 | self.value = value 161 | 162 | def __call__(self, tree): 163 | if tree.token.type == self.key: 164 | if self.value is None or self.value == tree.token.text: 165 | yield tree 166 | 167 | def __str__(self): 168 | val = '' if self.value is None else '={0}'.format(self.value) 169 | return 'Type({0}{1}:{2})'.format(tokens.map[self.key], val, self.key) 170 | 171 | 172 | class Star(Selector): 173 | """ * select any 174 | 175 | Similar to the * selector in CSS. 176 | """ 177 | def __call__(self, tree): 178 | yield tree 179 | 180 | def __str__(self): 181 | return 'Star(*)' 182 | 183 | 184 | class Descendant(Selector): 185 | """ E & F select any F that is a descendant of E """ 186 | 187 | def __init__(self, e, f): 188 | self.e, self.f = e, f 189 | 190 | def __call__(self, tree): 191 | for ftree in self.f(tree): 192 | root, ftree = ftree, ftree.parent 193 | while ftree: 194 | for etree in self.e(ftree): 195 | yield root 196 | ftree = ftree.parent 197 | 198 | def __str__(self): 199 | return 'Descendant({0} & {1})'.format(self.e, self.f) 200 | 201 | 202 | class AdjacentSibling(Selector): 203 | """ E + F select any F immediately preceded by a sibling E """ 204 | 205 | def __init__(self, e, f): 206 | self.e, self.f = e, f 207 | 208 | def __call__(self, node): 209 | if not node.parent: 210 | return 211 | for ftree in self.f(node): 212 | index = node.parent.children.index(ftree) 213 | if not index: 214 | return 215 | previous = node.parent.children[index-1] 216 | for child in self.e(previous): 217 | yield ftree 218 | 219 | def __str__(self): 220 | return 'AdjacentSibling({} + {})'.format(self.e, self.f) 221 | 222 | 223 | class AnySibling(Selector): 224 | """ E / F select any F preceded by a sibling E """ 225 | 226 | def __init__(self, e, f): 227 | self.e, self.f = e, f 228 | 229 | def __call__(self, node): 230 | if not node.parent: 231 | return 232 | for ftree in self.f(node): 233 | index = node.parent.children.index(ftree) 234 | if not index: 235 | return 236 | for prev in node.parent.children[:index]: 237 | for child in self.e(prev): 238 | yield ftree 239 | 240 | def __str__(self): 241 | return 'AnySibling({} / {})'.format(self.e, self.f) 242 | -------------------------------------------------------------------------------- /java2python/lib/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.lib -> common library bits. 4 | 5 | from functools import partial 6 | 7 | 8 | class FS(object): 9 | """ Format string abbreviations. """ 10 | l = '{left}' 11 | r = '{right}' 12 | c = ':' 13 | lc = l + c 14 | lr = l + r 15 | lsr = l + ' ' + r 16 | lsrc = lsr + c 17 | 18 | @classmethod 19 | def op(cls, op): 20 | """ Returns a format string for the given operation. """ 21 | l, r = cls.l, cls.r 22 | if op == '>>>': 23 | return '(' + l + ' & (2**32+' + l + ')) >> ' + r 24 | if op == '>>>=': 25 | return l + ' = bsr(' + l + ', ' + r + ')' 26 | return l + ' ' + op + ' ' + r 27 | 28 | 29 | escapes = { 30 | 'BLACK' : '\033[90m', 31 | 'BLUE' : '\033[94m', 32 | 'CYAN' : '\033[96m', 33 | 'GREEN' : '\033[92m', 34 | 'MAGENTA' : '\033[95m', 35 | 'NORMAL' : '\033[0m', 36 | 'RED' : '\033[91m', 37 | 'WHITE' : '\033[97m', 38 | 'YELLOW' : '\033[93m', 39 | } 40 | 41 | 42 | def escape(color, value): 43 | return escapes.get(color, '') + str(value) + escapes.get('NORMAL', '') 44 | 45 | 46 | class colors: 47 | black = partial(escape, 'BLACK') 48 | blue = partial(escape, 'BLUE') 49 | cyan = partial(escape, 'CYAN') 50 | green = partial(escape, 'GREEN') 51 | magenta = partial(escape, 'MAGENTA') 52 | red = partial(escape, 'RED') 53 | white = partial(escape, 'WHITE') 54 | yellow = partial(escape, 'YELLOW') 55 | -------------------------------------------------------------------------------- /java2python/mod/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.mod -> provides simple modification routines for the 4 | # library and projects using it. 5 | # 6 | # The java2python.mod.basic module contains various functions for 7 | # sprinkling generated source with docstrings, comments, decorators, 8 | # etc. 9 | # 10 | # The java2python.mod.inclues module contains functions that the 11 | # library will include directly -- as source code -- in the generated 12 | # output. 13 | # 14 | # The java2python.mod.transform module contains values and functions 15 | # for transforming input AST nodes. 16 | -------------------------------------------------------------------------------- /java2python/mod/basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.mod.basic -> functions to revise generated source strings. 4 | 5 | from itertools import count 6 | from logging import info, warn 7 | from os import path 8 | from re import sub as rxsub 9 | 10 | from java2python.lib import FS 11 | 12 | 13 | def shebangLine(module): 14 | """ yields the canonical python shebang line. """ 15 | yield '#!/usr/bin/env python' 16 | 17 | 18 | def encodingLine(encoding='utf-8'): 19 | """ returns a function to yield the specified encoding line. 20 | 21 | Note that this function isn't wired up because the encoding is 22 | specified for the source directly, and adding this line produces a 23 | syntax error when the compile function is used. 24 | """ 25 | def line(module): 26 | yield '# -*- coding: {0} -*-'.format(encoding) 27 | return line 28 | 29 | 30 | def simpleDocString(obj): 31 | """ yields multiple lines for a default docstring. 32 | 33 | This generator works for modules, classes, and functions. 34 | """ 35 | yield '""" generated source for {0} {1} """'.format(obj.typeName, obj.name) 36 | 37 | 38 | def commentedImports(module, expr): 39 | module.factory.comment(parent=module, left=expr, fs='#import {left}') 40 | 41 | 42 | def simpleImports(module, expr): 43 | module.factory.expr(parent=module, left=expr, fs='import {left}') 44 | 45 | 46 | def commentedPackages(module, expr): 47 | module.factory.comment(parent=module, left=expr, fs='# package: {left}') 48 | 49 | 50 | def namespacePackages(module, expr): 51 | source = module.sourceFilename 52 | if not source: 53 | warn('namespace package not created; source input not named.') 54 | return 55 | initname = path.join(path.dirname(source), '__init__.py') 56 | if path.exists(initname): 57 | warn('namespace package not created; __init__.py exists.') 58 | return 59 | with open(initname, 'w') as initfile: 60 | initfile.write('from pkgutil import extend_path\n') 61 | initfile.write('__path__ = extend_path(__path__, __name__)\n') 62 | # wrong 63 | initfile.write('\nfrom {0} import {0}\n'.format(module.name)) 64 | info('created __init__.py file for package %s.', expr) 65 | 66 | 67 | def enumConstInts(enum, index, name): 68 | return str(index) 69 | 70 | 71 | def enumConstStrings(enum, index, name): 72 | return repr(name) 73 | 74 | 75 | scriptTemplate = """\n 76 | if __name__ == '__main__': 77 | {indent}import sys 78 | {indent}{name}.main(sys.argv)""" 79 | 80 | 81 | def scriptMainStanza(module): 82 | def filterClass(x): 83 | return x.isClass and x.name==module.name 84 | 85 | def filterMethod(x): 86 | return x.isMethod and x.isPublic and x.isStatic and \ 87 | x.isVoid and x.name=='main' 88 | 89 | for cls in [c for c in module.children if filterClass(c)]: 90 | if [m for m in cls.children if filterMethod(m)]: 91 | yield scriptTemplate.format(indent=module.indent, name=module.name) 92 | break 93 | 94 | 95 | def outputSubs(obj, text): 96 | subsname = '{0}OutputSubs'.format(obj.typeName) 97 | subs = obj.config.every(subsname, []) 98 | for sub in subs: 99 | for pattern, repl in sub: 100 | text = rxsub(pattern, repl, text) 101 | return text 102 | 103 | 104 | def overloadedClassMethods(method): 105 | """ 106 | NB: this implementation does not handle overloaded static (or 107 | class) methods, only instance methods. 108 | """ 109 | cls = method.parent 110 | methods = [o for o in cls.children if o.isMethod and o.name==method.name] 111 | if len(methods) == 1: 112 | if methods[0].overloaded: 113 | yield methods[0].overloaded 114 | return 115 | for i, m in enumerate(methods[1:]): 116 | args = [p['type'] for p in m.parameters] 117 | args = ', '.join(args) 118 | m.overloaded = '@{0}.register({1})'.format(method.name, args) 119 | m.name = '{0}_{1}'.format(method.name, i) 120 | # for this one only: 121 | yield '@overloaded' 122 | 123 | 124 | def maybeClassMethod(method): 125 | if method.isStatic and 'classmethod' not in method.decorators: 126 | yield '@classmethod' 127 | 128 | 129 | def maybeAbstractMethod(method): 130 | if method.parent and method.parent.isInterface: 131 | yield '@abstractmethod' 132 | 133 | 134 | def maybeSynchronizedMethod(method): 135 | if 'synchronized' in method.modifiers: 136 | yield '@synchronized' 137 | 138 | 139 | def globalNameCounter(original, counter=count()): 140 | return '__{0}_{1}'.format(original, counter.next()) 141 | 142 | 143 | def getBsrSrc(): 144 | from inspect import getsource 145 | from java2python.mod.include.bsr import bsr 146 | return getsource(bsr) 147 | 148 | 149 | def getSyncHelpersSrc(): 150 | from inspect import getsource 151 | from java2python.mod.include import sync 152 | return getsource(sync) 153 | 154 | 155 | def maybeBsr(module): 156 | if getattr(module, 'needsBsrFunc', False): 157 | for line in getBsrSrc().split('\n'): 158 | yield line 159 | 160 | 161 | def maybeAbstractHelpers(module): 162 | if getattr(module, 'needsAbstractHelpers', False): 163 | yield 'from abc import ABCMeta, abstractmethod' 164 | 165 | 166 | def maybeSyncHelpers(module): 167 | if getattr(module, 'needsSyncHelpers', False): 168 | for line in getSyncHelpersSrc().split('\n'): 169 | yield line 170 | 171 | 172 | def classContentSort(obj): 173 | isMethod = lambda x:x and x.isMethod 174 | 175 | def iterBody(body): 176 | group = [] 177 | for value in body: 178 | if isMethod(value): 179 | group.append(value) 180 | yield group 181 | group = [] 182 | else: 183 | group.append(value) 184 | yield group 185 | 186 | def sortBody(group): 187 | methods = [item for item in group if isMethod(item)] 188 | return methods[0].name if methods else -1 189 | 190 | grp = list(iterBody(obj.children)) 191 | grpsrt = sorted(grp, key=sortBody) 192 | obj.children = [item for grp in grpsrt for item in grp] 193 | 194 | 195 | def defaultParams(obj): 196 | return iter(obj.parameters) 197 | 198 | 199 | def zopeInterfaceMethodParams(obj): 200 | if not obj.parent.isInterface: 201 | for param in obj.parameters: 202 | yield param 203 | else: 204 | for index, param in enumerate(obj.parameters): 205 | if index != 0 and param['name'] != 'self': 206 | yield param 207 | 208 | 209 | normalBases = ('object', ) 210 | 211 | 212 | def defaultBases(obj): 213 | return iter(obj.bases or normalBases) 214 | 215 | 216 | def zopeInterfaceBases(obj): 217 | return iter(obj.bases or ['zope.interface.Interface']) 218 | 219 | 220 | def implAny(obj): 221 | for module in obj.parents(lambda x:x.isModule): 222 | for name in obj.bases: 223 | if any(module.find(lambda v:v.name == name)): 224 | return True 225 | 226 | 227 | def zopeImplementsClassBases(obj): 228 | return iter(normalBases) if implAny(obj) else defaultBases(obj) 229 | 230 | 231 | def zopeImplementsClassHead(obj): 232 | if implAny(obj): 233 | for cls in obj.bases: 234 | yield 'zope.interface.implements({})'.format(cls) 235 | 236 | 237 | def moveStaticExpressions(cls): 238 | name = '{}.'.format(cls.name) # notice the dot 239 | exprs = [child for child in cls.children if child.isExpression and name in str(child)] 240 | module = cls.parents(lambda x:x.isModule).next() 241 | for expr in exprs: 242 | cls.children.remove(expr) 243 | newExpr = module.factory.expr(fs=name + '{right}', right=expr) 244 | module.adopt(newExpr, index=len(module.children)) 245 | 246 | 247 | def castCtor(expr, node): 248 | expr.fs = FS.l + '(' + FS.r + ')' 249 | 250 | 251 | def castDrop(expr, node): 252 | expr.fs = FS.r 253 | -------------------------------------------------------------------------------- /java2python/mod/include/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natural/java2python/b8037561c542522ae620e0a071ecc7e668461587/java2python/mod/include/__init__.py -------------------------------------------------------------------------------- /java2python/mod/include/bsr.py: -------------------------------------------------------------------------------- 1 | def bsr(value, bits): 2 | """ bsr(value, bits) -> value shifted right by bits 3 | 4 | This function is here because an expression in the original java 5 | source contained the token '>>>' and/or '>>>=' (bit shift right 6 | and/or bit shift right assign). In place of these, the python 7 | source code below contains calls to this function. 8 | 9 | Copyright 2003 Jeffrey Clement. See pyrijnadel.py for license and 10 | original source. 11 | """ 12 | minint = -2147483648 13 | if bits == 0: 14 | return value 15 | elif bits == 31: 16 | if value & minint: 17 | return 1 18 | else: 19 | return 0 20 | elif bits < 0 or bits > 31: 21 | raise ValueError('bad shift count') 22 | tmp = (value & 0x7FFFFFFE) // 2**bits 23 | if (value & minint): 24 | return (tmp | (0x40000000 // 2**(bits-1))) 25 | else: 26 | return tmp 27 | -------------------------------------------------------------------------------- /java2python/mod/include/classmethod.py: -------------------------------------------------------------------------------- 1 | class classmethod_(classmethod): 2 | """ Classmethod that provides attribute delegation. 3 | 4 | """ 5 | def __getattr__(self, name): 6 | return getattr(self.__func__, name) 7 | -------------------------------------------------------------------------------- /java2python/mod/include/overloading.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.5 2 | 3 | ## 4 | # Dynamically overloaded functions. 5 | # 6 | # This is an implementation of (dynamically, or run-time) overloaded 7 | # functions; also known as generic functions or multi-methods. 8 | # 9 | # This module is from Python SVN, 10 | # http://svn.python.org/view/sandbox/trunk/overload/overloading.py 11 | ## 12 | 13 | """Dynamically overloaded functions. 14 | 15 | This is an implementation of (dynamically, or run-time) overloaded 16 | functions; also known as generic functions or multi-methods. 17 | 18 | The dispatch algorithm uses the types of all argument for dispatch, 19 | similar to (compile-time) overloaded functions or methods in C++ and 20 | Java. 21 | 22 | Most of the complexity in the algorithm comes from the need to support 23 | subclasses in call signatures. For example, if an function is 24 | registered for a signature (T1, T2), then a call with a signature (S1, 25 | S2) is acceptable, assuming that S1 is a subclass of T1, S2 a subclass 26 | of T2, and there are no other more specific matches (see below). 27 | 28 | If there are multiple matches and one of those doesn't *dominate* all 29 | others, the match is deemed ambiguous and an exception is raised. A 30 | subtlety here: if, after removing the dominated matches, there are 31 | still multiple matches left, but they all map to the same function, 32 | then the match is not deemed ambiguous and that function is used. 33 | Read the method find_func() below for details. 34 | 35 | Python 2.5 is required due to the use of predicates any() and all(). 36 | 37 | """ 38 | 39 | from types import MethodType as instancemethod 40 | 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 46 | 47 | 48 | class overloaded: 49 | """An implementation of overloaded functions.""" 50 | 51 | def __init__(self, default_func): 52 | # Decorator to declare new overloaded function. 53 | self.registry = {} 54 | self.cache = {} 55 | self.default_func = default_func 56 | 57 | def __get__(self, obj, type=None): 58 | if obj is None: 59 | return self 60 | return instancemethod(self, obj) 61 | 62 | def register(self, *types): 63 | """Decorator to register an implementation for a specific set of types. 64 | 65 | .register(t1, t2)(f) is equivalent to .register_func((t1, t2), f). 66 | 67 | """ 68 | def helper(func): 69 | self.register_func(types, func) 70 | return func 71 | return helper 72 | 73 | def register_func(self, types, func): 74 | """Helper to register an implementation.""" 75 | self.registry[tuple(types)] = func 76 | self.cache = {} # Clear the cache (later we can optimize this). 77 | 78 | def __call__(self, *args): 79 | """Call the overloaded function.""" 80 | types = tuple(map(type, args)) 81 | func = self.cache.get(types) 82 | if func is None: 83 | self.cache[types] = func = self.find_func(types) 84 | return func(*args) 85 | 86 | def find_func(self, types): 87 | """Find the appropriate overloaded function; don't call it. 88 | 89 | This won't work for old-style classes or classes without __mro__. 90 | 91 | """ 92 | func = self.registry.get(types) 93 | if func is not None: 94 | # Easy case -- direct hit in registry. 95 | return func 96 | 97 | # XXX Phillip Eby suggests to use issubclass() instead of __mro__. 98 | # There are advantages and disadvantages. 99 | 100 | # I can't help myself -- this is going to be intense functional code. 101 | # Find all possible candidate signatures. 102 | mros = tuple(t.__mro__ for t in types) 103 | n = len(mros) 104 | candidates = [sig for sig in self.registry 105 | if len(sig) == n and 106 | all(t in mro for t, mro in zip(sig, mros))] 107 | if not candidates: 108 | # No match at all -- use the default function. 109 | return self.default_func 110 | if len(candidates) == 1: 111 | # Unique match -- that's an easy case. 112 | return self.registry[candidates[0]] 113 | 114 | # More than one match -- weed out the subordinate ones. 115 | 116 | def dominates(dom, sub, 117 | orders=tuple(dict((t, i) for i, t in enumerate(mro)) 118 | for mro in mros)): 119 | # Predicate to decide whether dom strictly dominates sub. 120 | # Strict domination is defined as domination without equality. 121 | # The arguments dom and sub are type tuples of equal length. 122 | # The orders argument is a precomputed auxiliary data structure 123 | # giving dicts of ordering information corresponding to the 124 | # positions in the type tuples. 125 | # A type d dominates a type s iff order[d] <= order[s]. 126 | # A type tuple (d1, d2, ...) dominates a type tuple of equal length 127 | # (s1, s2, ...) iff d1 dominates s1, d2 dominates s2, etc. 128 | if dom is sub: 129 | return False 130 | return all(order[d] <= order[s] 131 | for d, s, order in zip(dom, sub, orders)) 132 | 133 | # I suppose I could inline dominates() but it wouldn't get any clearer. 134 | candidates = [cand 135 | for cand in candidates 136 | if not any(dominates(dom, cand) for dom in candidates)] 137 | if len(candidates) == 1: 138 | # There's exactly one candidate left. 139 | return self.registry[candidates[0]] 140 | 141 | # Perhaps these multiple candidates all have the same implementation? 142 | funcs = set(self.registry[cand] for cand in candidates) 143 | if len(funcs) == 1: 144 | return funcs.pop() 145 | 146 | # No, the situation is irreducibly ambiguous. 147 | raise TypeError("ambigous call; types=%r; candidates=%r" % 148 | (types, candidates)) 149 | -------------------------------------------------------------------------------- /java2python/mod/include/sync.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from threading import RLock 3 | 4 | def lock_for_object(obj, locks={}): 5 | return locks.setdefault(id(obj), RLock()) 6 | 7 | def synchronized(call): 8 | assert call.__code__.co_varnames[0] in ['self', 'cls'] 9 | @wraps(call) 10 | def inner(*args, **kwds): 11 | with lock_for_object(args[0]): 12 | return call(*args, **kwds) 13 | return inner 14 | -------------------------------------------------------------------------------- /java2python/mod/include/sync_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from threading import RLock 4 | 5 | _locks = {} 6 | def lock_for_object(obj, locks=_locks): 7 | return locks.setdefault(id(obj), RLock()) 8 | 9 | def synchronized(call): 10 | def inner(*args, **kwds): 11 | with lock_for_object(call): 12 | return call(*args, **kwds) 13 | return inner 14 | 15 | class Main(object): 16 | 17 | def __init__(self): 18 | self.attr = object() 19 | 20 | def b1(self): 21 | r = [] 22 | with lock_for_object(self.attr): 23 | r.append(0) 24 | return r 25 | 26 | def b2(self): 27 | r = [] 28 | with lock_for_object(self.attr): 29 | r.append(0) 30 | return r 31 | 32 | def m1(self): 33 | return id(lock_for_object(self)) 34 | 35 | def m2(self): 36 | return id(lock_for_object(self)) 37 | 38 | @classmethod 39 | def c1(cls): 40 | return id(lock_for_object(cls)) 41 | 42 | @classmethod 43 | def c2(cls): 44 | return id(lock_for_object(cls)) 45 | 46 | @synchronized 47 | def s1(self, *values, **kwargs): 48 | return [values, kwargs] 49 | 50 | @synchronized 51 | def s2(self, *values, **kwargs): 52 | return [values, kwargs] 53 | 54 | @classmethod 55 | @synchronized 56 | def cs1(cls, *values, **kwargs): 57 | return [cls, values, kwargs] 58 | 59 | @classmethod 60 | @synchronized 61 | def cs2(cls, *values, **kwargs): 62 | return [cls, values, kwargs] 63 | 64 | 65 | 66 | if __name__ == '__main__': 67 | x = Main() 68 | expected_count = 0 69 | 70 | assert x.b1() == x.b2() 71 | expected_count += 1 # one for the attr, used twice 72 | 73 | assert x.c1() == x.c2() 74 | expected_count += 1 # one for the class, used twice 75 | 76 | assert x.m1() == x.m2() 77 | expected_count += 1 # one for the instance, used twice 78 | 79 | assert x.s1() == x.s2() 80 | expected_count += 2 # one for each instance method 81 | 82 | assert x.cs1() == x.cs2() 83 | expected_count += 2 # one for each class method 84 | 85 | assert expected_count == len(_locks) 86 | 87 | print '[PASS]' 88 | 89 | -------------------------------------------------------------------------------- /java2python/mod/transform.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # java2python.mod.transform -> input AST transformer functions and constants. 4 | # 5 | # This module provides several transformation functions which are 6 | # simple callables that modify AST nodes. These functions are not 7 | # responsible for selecting nodes, only changing the node content. 8 | # This gives us AST generation decoupled from AST traversal and 9 | # modification. 10 | # 11 | # See the java2python.config.default and java2python.lang.selector modules to 12 | # understand how and when selectors are associated with these callables. 13 | 14 | import re 15 | from logging import warn 16 | 17 | import keyword 18 | import types 19 | 20 | from java2python.lang import tokens 21 | 22 | 23 | def invalidPythonNames(): 24 | """ Creates a list of valid Java identifiers that are invalid in Python. """ 25 | ts = [getattr(types, n) for n in dir(types) if not n.startswith('_')] 26 | ns = [t.__name__ for t in ts if isinstance(t, type)] 27 | return ['None', 'True', 'False', ] + ns + keyword.kwlist 28 | 29 | 30 | def keywordSafeIdent(node, config, invalid=invalidPythonNames()): 31 | """ Validates and possibly renames a Java identifier. """ 32 | ident = node.token.text 33 | if ident in invalid: 34 | node.token.text = '%s_' % ident 35 | 36 | 37 | def makeConst(v): 38 | """ Returns a closure that indiscriminately changes node text to a value. """ 39 | def xform(node, config): 40 | node.token.text = v 41 | return xform 42 | 43 | 44 | # Create transformers for mapping well-known Java idents into their 45 | # Python counterparts: 46 | null2None = makeConst('None') 47 | false2False = makeConst('False') 48 | true2True = makeConst('True') 49 | 50 | 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 | 59 | def syntaxSafeFloatLiteral(node, config): 60 | """ Ensures a Java float literal is a valid Python float literal. """ 61 | value = node.token.text 62 | if value.startswith('.'): 63 | value = '0' + value 64 | if value.lower().endswith(('f', 'd')): 65 | value = value[:-1] 66 | node.token.text = value 67 | 68 | 69 | def lengthToLen(node, config): 70 | """ Transforms expressions like 'value.length()' to 'len(value)'. 71 | 72 | This method changes AST branches like this: 73 | 74 | METHOD_CALL [start=45, stop=49] 75 | DOT . [line=4, start=45, stop=47] 76 | IDENT foo [line=4, start=45] 77 | IDENT length [line=4, start=47] 78 | ARGUMENT_LIST [line=4, start=48, stop=49] 79 | 80 | Into branches like this: 81 | 82 | IDENT len(foo) [line=4, start=45] 83 | 84 | Notice that the resulting IDENT node text is invalid. We can't use a 85 | METHOD_CALL token because those are always bound to a class or instance. 86 | It would be best to add a new token type, and that option will be explored 87 | if we run into this problem again. 88 | 89 | """ 90 | dot = node.parent 91 | method = dot.parent 92 | 93 | ident = dot.firstChildOfType(tokens.IDENT) 94 | ident.token.text = 'len({})'.format(ident.text) 95 | 96 | expr = method.parent 97 | expr.children.remove(method) 98 | expr.addChild(ident) 99 | 100 | 101 | def formatSyntaxTransf(match): 102 | """ Helper function for formatString AST transform. 103 | 104 | Translates the Java Formatter syntax into Python .format syntax. 105 | 106 | This function gets called by re.sub which matches all the %...$... groups 107 | inside a format specifier string. 108 | """ 109 | groups = match.groupdict() 110 | if groups['convers'] == 'n': 111 | # Means platform-specific line separator 112 | return '\\n' # Py converts \n to os.linesep 113 | 114 | result = '{' 115 | thous_sep = '' 116 | 117 | if(groups['idx']): 118 | idx = int(groups['idx'][:-1]) 119 | result += str(idx - 1) # Py starts count from 0 120 | result += ':' 121 | 122 | if(groups['flags']): 123 | if ',' in groups['flags']: 124 | thous_sep = ',' 125 | if '+' in groups['flags']: 126 | result += '+' 127 | elif ' ' in groups['flags']: 128 | result += ' ' 129 | if '#' in groups['flags']: 130 | result += '#' 131 | if '0' in groups['flags']: 132 | result += '0' 133 | 134 | if(groups['width']): 135 | result += groups['width'] 136 | result += thous_sep 137 | 138 | if(groups['precision']): 139 | result += groups['precision'] 140 | 141 | result += groups['convers'] + '}' 142 | 143 | return result 144 | 145 | def formatString(node, config): 146 | """ Transforms string formatting like 'String.format("%d %2$s", i, s)' 147 | into '"{:d} {2:s}".format(i, s)'. 148 | """ 149 | dot = node.parent 150 | method = dot.parent 151 | arg_list = method.firstChildOfType(tokens.ARGUMENT_LIST) 152 | call_args = [arg for arg in arg_list.childrenOfType(tokens.EXPR)] 153 | args = [arg.firstChildOfType(tokens.IDENT) for arg in call_args[1:]] 154 | 155 | # Translate format syntax (if format == string_literal) 156 | format = call_args[0].firstChildOfType(tokens.STRING_LITERAL) 157 | if format: 158 | format.token.text = \ 159 | re.sub(r'%(?P\d+\$)?(?P[-+# 0,]+)?(?P[0-9]+)?(?P\.[0-9]+)?(?P[scdoxefgn])', 160 | formatSyntaxTransf, 161 | format.token.text, 162 | flags=re.IGNORECASE) 163 | else: 164 | # Translation should happen at runtime 165 | format = call_args[0].firstChild() 166 | if format.type == tokens.IDENT: 167 | # String variable 168 | warn('Formatting string %s is not automatically translated.' 169 | % str(format.token.text)) 170 | else: 171 | # Function that returns String 172 | warn('Formatting string returned by %s() is not automatically translated.' 173 | % str(format.firstChildOfType(tokens.IDENT).token.text)) 174 | 175 | left_ident = dot.children[0] 176 | right_ident = dot.children[1] 177 | 178 | # Change AST 179 | arg_list.children.remove(format.parent) 180 | dot.children.remove(left_ident) 181 | dot.children.remove(right_ident) 182 | dot.addChild(format) 183 | dot.addChild(right_ident) 184 | 185 | 186 | def typeSub(node, config): 187 | """ Maps specific, well-known Java types to their Python counterparts. 188 | 189 | See the `java2python.config.default` module for the default type 190 | mapping and further discussion. 191 | """ 192 | ident = node.token.text 193 | for subs in reversed(config.every('typeSubs', {})): 194 | if ident in subs: 195 | node.token.text = subs[ident] 196 | return 197 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## java2python 2 | 3 | Simple but effective tool to translate Java source code into Python. 4 | 5 | 6 | The java2python package can translate any syntactically valid Java source code 7 | file. The generated Python code is not guaranteed to run, nor is guaranteed to 8 | be syntactically valid Python. However, java2python works well many cases, and 9 | in some of those, it creates perfectly usable and workable Python code. 10 | 11 | For more information, read the [introduction][]. To install, refer to the 12 | [installation][] page. 13 | 14 | There are [lots of docs][], [plenty of tests][], and [many options][] for 15 | controlling code generation. 16 | 17 | If you're looking for old releases, check the [downloads][] link above. 18 | 19 | Here's a very simple example: 20 | 21 | ```bash 22 | $ cat HelloWorld.java 23 | ``` 24 | ```java 25 | // This is the HelloWorld class with a single method. 26 | class HelloWorld { 27 | public static void main(String[] args) { 28 | System.out.println("Hello, world."); 29 | } 30 | } 31 | ``` 32 | 33 | Next we run our program: 34 | 35 | 36 | ```bash 37 | $ j2py HelloWorld.java 38 | ``` 39 | ```python 40 | #!/usr/bin/env python 41 | """ generated source for module HelloWorld """ 42 | 43 | # This is the HelloWorld class with a single method. 44 | class HelloWorld(object): 45 | """ generated source for class HelloWorld """ 46 | 47 | @classmethod 48 | def main(cls, args): 49 | """ generated source for method main """ 50 | print "Hello, world." 51 | 52 | if __name__ == '__main__': 53 | import sys 54 | HelloWorld.main(sys.argv) 55 | ``` 56 | 57 | 58 | [downloads]: https://github.com/natural/java2python/downloads 59 | [installation]: https://github.com/natural/java2python/tree/master/doc/install.md 60 | [introduction]: https://github.com/natural/java2python/tree/master/doc/intro.md 61 | [lots of docs]: https://github.com/natural/java2python/tree/master/doc/ 62 | [many options]: https://github.com/natural/java2python/tree/master/doc/customization.md 63 | [plenty of tests]: https://github.com/natural/java2python/tree/master/doc/tests.md 64 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ setup.py -> java2python setup script. 4 | 5 | Simple but effective tool to translate Java source code into Python. 6 | 7 | This package provides tools to imperfectly translate Java source code to 8 | Python source code. 9 | 10 | This version requires Python 2.7. 11 | """ 12 | 13 | from distutils.core import setup 14 | from os import path, listdir 15 | 16 | 17 | classifiers = """ 18 | Development Status :: 4 - Beta 19 | Intended Audience :: Developers 20 | License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) 21 | Natural Language :: English 22 | Operating System :: OS Independent 23 | Operating System :: POSIX 24 | Programming Language :: Python 25 | Programming Language :: Java 26 | Topic :: Software Development 27 | Topic :: Software Development :: Code Generators 28 | """ 29 | 30 | 31 | description = __doc__.split('\n')[2] 32 | long_description = '\n'.join(__doc__.split('\n')[4:]) 33 | 34 | 35 | def doc_files(): 36 | return [path.join('doc', name) for name in listdir('doc')] 37 | 38 | 39 | setup( 40 | name='java2python', 41 | version='0.5.1', 42 | 43 | description=description, 44 | long_description=long_description, 45 | 46 | author='Troy Melhase', 47 | author_email='troy@troy.io', 48 | 49 | url='https://github.com/natural/java2python/', 50 | download_url='https://github.com/downloads/natural/java2python/java2python-0.5.1.tar.gz', 51 | 52 | keywords=['java', 'java2python', 'compiler'], 53 | classifiers=filter(None, classifiers.split('\n')), 54 | 55 | packages=[ 56 | 'java2python', 57 | 'java2python.compiler', 58 | 'java2python.config', 59 | 'java2python.lang', 60 | 'java2python.lib', 61 | 'java2python.mod', 62 | 'java2python.mod.include', 63 | ], 64 | 65 | package_data={ 66 | 'java2python' : [ 67 | 'license.txt', 68 | 'readme.md', 69 | ], 70 | 'java2python.lang': [ 71 | '*.g', 72 | '*.tokens', 73 | ] 74 | }, 75 | 76 | scripts=[ 77 | 'bin/j2py', 78 | ], 79 | 80 | data_files=[ 81 | ('doc', doc_files()), 82 | ], 83 | 84 | install_requires=['antlr_python_runtime==3.1.3'], 85 | 86 | ) 87 | -------------------------------------------------------------------------------- /test/Anno0.java: -------------------------------------------------------------------------------- 1 | @interface Example {} 2 | 3 | @Example 4 | public class Anno0 { 5 | public static void main(String[] args) { 6 | System.out.println(0); 7 | } 8 | } -------------------------------------------------------------------------------- /test/Anno1.java: -------------------------------------------------------------------------------- 1 | @interface AnnoEx { 2 | String title() default "simple string"; 3 | int value() default 0; 4 | } 5 | 6 | 7 | 8 | 9 | 10 | @AnnoEx(value=3, title="asdf") 11 | class Anno1 { 12 | 13 | @AnnoEx 14 | public static void zero() {} 15 | 16 | @AnnoEx(1) 17 | public static void one() {} 18 | 19 | @AnnoEx(value=2, title="bar") 20 | public static void two() {} 21 | 22 | public static void main(String[] args) { 23 | System.out.println("a"); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /test/Anno2.java: -------------------------------------------------------------------------------- 1 | @interface AnnotationExample { 2 | int id(); 3 | String title() default "unset"; 4 | 5 | public static final int a = 3; 6 | 7 | int y = 3; 8 | public class InnerAnno { 9 | int z = 3; 10 | public void bar(int x) { 11 | } 12 | } 13 | 14 | 15 | } 16 | 17 | 18 | @AnnotationExample(id=1) 19 | class Anno2 { 20 | public static void main(String[] args) { 21 | System.out.println("a"); 22 | } 23 | 24 | @AnnotationExample(id=2, title="test method") 25 | public static int foo(int a) { 26 | System.out.println(a); 27 | return a; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /test/Anno3.java: -------------------------------------------------------------------------------- 1 | class Outer { 2 | } 3 | 4 | @interface TestAnno { 5 | int id(); 6 | String title() default "unset"; 7 | 8 | public static final int a = 3; 9 | 10 | class Inner { 11 | private static int a = 4; 12 | public int bar(String a) { 13 | System.out.println(a); 14 | return 0; 15 | } 16 | } 17 | } 18 | 19 | @interface Marker {} 20 | 21 | @Marker 22 | @TestAnno(id=1) 23 | class Anno3 { 24 | public static void main(String[] args) { 25 | System.out.println("a"); 26 | } 27 | 28 | @TestAnno(id=2, title="test method") 29 | @Marker public static int foo(int a) { 30 | System.out.println(a); 31 | return a; 32 | } 33 | 34 | @Marker 35 | public void bar() { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/Array0.java: -------------------------------------------------------------------------------- 1 | class Array0 { 2 | static int a[] = {1, 2, 3}; 3 | 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/Array1.java: -------------------------------------------------------------------------------- 1 | public class Array1 { 2 | static Integer a[] = {1, 2, 3}; 3 | 4 | void foo(int i) { 5 | System.out.println( a[i] ); 6 | } 7 | 8 | public static void main(String[] args) { 9 | Array1 ar = new Array1(); 10 | ar.foo(0); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Array2.java: -------------------------------------------------------------------------------- 1 | public class Array2 { 2 | public static void main(String[] args) { 3 | Integer b[] = {4, 5, 6}; 4 | System.out.println(b[0].toString()); 5 | System.out.println(b[1].toString()); 6 | System.out.println(b[2].toString()); 7 | 8 | int c[] = {1,2,3}; 9 | System.out.println(c[0]); 10 | System.out.println(c[1]); 11 | System.out.println(c[2]); 12 | 13 | String d[] = {"a", "s", "d", "f"}; 14 | System.out.println(d[0]); 15 | System.out.println(d[1]); 16 | System.out.println(d[2]); 17 | System.out.println(d[3]); 18 | 19 | String[] e; 20 | e = new String[2]; 21 | e[0] = "4"; 22 | e[1] = "2"; 23 | System.out.println(e[0]); 24 | System.out.println(e[1]); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/Array3.java: -------------------------------------------------------------------------------- 1 | public class Array3 { 2 | public static void main(String[] args) { 3 | Integer b[] = {4, 5, 6, 12}; 4 | int x = 0; 5 | int y = 1; 6 | 7 | System.out.println(b[y+x+x+1+x+y].toString()); 8 | System.out.println(b[1].toString()); 9 | System.out.println(b[2].toString()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Assert0.java: -------------------------------------------------------------------------------- 1 | class Assert0 { 2 | public static void main(String[] args) { 3 | int x = 1; 4 | assert x>0; 5 | assert x==1: "not"; 6 | 7 | int y = 3; 8 | try { 9 | assert x==0; 10 | 11 | } catch (AssertionError e) { 12 | System.out.println(y); 13 | } catch (IndexOutOfBoundsException e) { 14 | System.out.println(y); 15 | } 16 | } 17 | } 18 | 19 | // assert x == 0: y; 20 | -------------------------------------------------------------------------------- /test/Assign0.java: -------------------------------------------------------------------------------- 1 | class Assign0 { 2 | public static void main(String[] args) { 3 | int x = 3; 4 | System.out.println(x); 5 | 6 | x = 1; 7 | System.out.println(x); 8 | 9 | x += 2; 10 | System.out.println(x); 11 | 12 | x -= 10; 13 | System.out.println(x); 14 | 15 | x *= 2; 16 | System.out.println(x); 17 | 18 | x /= 14; 19 | System.out.println(x); 20 | 21 | x = 6; 22 | x &= 2; 23 | System.out.println(x); 24 | 25 | x = 10; 26 | x |= 3; 27 | System.out.println(x); 28 | 29 | x = 10; 30 | x ^= 3; 31 | System.out.println(x); 32 | 33 | x = 10; 34 | x %= 3; 35 | System.out.println(x); 36 | 37 | x = 3; 38 | x <<= 1; 39 | System.out.println(x); 40 | 41 | x = 10; 42 | x >>= 1; 43 | System.out.println(x); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/Assign1.java: -------------------------------------------------------------------------------- 1 | class Assign1 { 2 | public static void main(String[] args) { 3 | int x = 42; 4 | System.out.println(x); 5 | 6 | x >>>= 1; 7 | System.out.println(x); 8 | x >>>= 3; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/BasicTypes0.java: -------------------------------------------------------------------------------- 1 | class BasicTypes0 { 2 | public static void main(String[] args) { 3 | 4 | byte B = 127; 5 | System.out.println(B); 6 | 7 | short S = 10240; 8 | System.out.println(S); 9 | 10 | char C = 'x'; 11 | System.out.println(C); 12 | 13 | int I = 48; 14 | System.out.println(I); 15 | 16 | 17 | long L = 1234567890; 18 | System.out.println(L); 19 | 20 | float F = 0.1f; 21 | System.out.println(F); 22 | 23 | double D = 0.1; 24 | System.out.println(D); 25 | 26 | boolean O = true; 27 | System.out.println(O ? 42 : -3); 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/BasicTypes1.java: -------------------------------------------------------------------------------- 1 | class BasicTypes1 { 2 | char chr; 3 | byte byt; 4 | short shr; 5 | int in_t; 6 | long lng; 7 | float flt; 8 | double dbl; 9 | 10 | public static void main(String[] args) { 11 | BasicTypes1 bt1 = new BasicTypes1(); 12 | System.out.println(bt1.byt); 13 | System.out.println(bt1.shr); 14 | System.out.println(bt1.in_t); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /test/BasicTypes2.java: -------------------------------------------------------------------------------- 1 | class BasicTypes2 { 2 | public static void main(String[] args) { 3 | 4 | Integer I = 32; 5 | System.out.println(I); 6 | 7 | Boolean B = true; 8 | System.out.println( B ? "ok" : "nope" ); 9 | 10 | Byte Y = 0; 11 | System.out.println(Y); 12 | 13 | Character C = 'c'; 14 | System.out.println(C); 15 | 16 | Short S = 128; 17 | System.out.println(S); 18 | 19 | Long L = 128L; 20 | System.out.println(L); 21 | 22 | Float F = 1.5F; 23 | System.out.println(F); 24 | 25 | Double D = 1.5; 26 | System.out.println(D); 27 | 28 | String T = "done"; 29 | System.out.println(T); 30 | 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/BasicTypes3.java: -------------------------------------------------------------------------------- 1 | class Vector {} 2 | 3 | class BasicTypes3 { 4 | Boolean B; 5 | Integer I; 6 | Double D; 7 | 8 | String S; 9 | Vector V; 10 | 11 | public static void main(String[] args) { 12 | BasicTypes3 bt3 = new BasicTypes3(); 13 | System.out.println(bt3.B == null ? 1 : 0); 14 | System.out.println(bt3.I == null ? 1 : 0); 15 | System.out.println(bt3.D == null ? 1 : 0); 16 | System.out.println(bt3.S == null ? 1 : 0); 17 | System.out.println(bt3.V == null ? 1 : 0); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /test/Break0.java: -------------------------------------------------------------------------------- 1 | class Break0 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | foo: 5 | while (x < 10) { 6 | if (x == 3) { 7 | break foo; 8 | } 9 | x++; 10 | System.out.println(x); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/Break1.java: -------------------------------------------------------------------------------- 1 | class Break1 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | while (x < 10) { 5 | if (x == 3) { 6 | break; 7 | } 8 | x++; 9 | System.out.println(x); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Cast0.java: -------------------------------------------------------------------------------- 1 | interface Something { 2 | public int foo(); 3 | } 4 | 5 | 6 | interface SomethingElse { 7 | public int foo(); 8 | } 9 | 10 | 11 | class Both implements Something { 12 | public int foo() { 13 | return 100; 14 | } 15 | } 16 | 17 | class What extends Both { 18 | public int foo() { 19 | return 200; 20 | } 21 | } 22 | 23 | 24 | class Cast0 { 25 | public static void main(String[] args) { 26 | int x = 33; 27 | Integer ix = (Integer) x; 28 | System.out.println(x); 29 | System.out.println(ix); 30 | 31 | What w = new What(); 32 | 33 | System.out.println( w.foo() ); 34 | 35 | Both b = (Both) w; 36 | 37 | System.out.println( b.foo() ); 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /test/Class00.java: -------------------------------------------------------------------------------- 1 | /* leading ml comment */ 2 | class /* sneaky 0 */ Class00 { // block line comment 3 | public static void main(String[] args) {} 4 | } 5 | -------------------------------------------------------------------------------- /test/Class01.java: -------------------------------------------------------------------------------- 1 | class Class01 { 2 | public static void main(String[] args) { 3 | System.out.println("Hello, world."); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/Class02.java: -------------------------------------------------------------------------------- 1 | // tests class variable initialization and reference 2 | class Class02 { 3 | public int w; 4 | public int x = 1; 5 | public int y, z = 2; 6 | public int a = 3, b; 7 | 8 | public static void main(String[] args) { 9 | Class02 c = new Class02(); 10 | System.out.println(c.w); 11 | System.out.println(c.x); 12 | System.out.println(c.y); 13 | System.out.println(c.z); 14 | System.out.println(c.a); 15 | System.out.println(c.b); 16 | c.b++; 17 | System.out.println(c.b); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/Class03.java: -------------------------------------------------------------------------------- 1 | // tests method calling with single argument 2 | class Class03 { 3 | public int m1(int x) { 4 | System.out.println(x); 5 | return x; 6 | } 7 | 8 | public static void main(String[] args) { 9 | Class03 c = new Class03(); 10 | System.out.println(c.m1(3)); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Class04.java: -------------------------------------------------------------------------------- 1 | // tests inner class instance declaration and creation 2 | class Class04 { 3 | static class StaticInner { 4 | public static String x = "notnull"; 5 | } 6 | 7 | int foo = 3; 8 | 9 | class NestedInner { 10 | public String y = "somenull"; 11 | } 12 | 13 | int bar = 4; 14 | 15 | public static void main(String[] args) { 16 | Class04 c4 = new Class04(); 17 | 18 | StaticInner si = new StaticInner(); 19 | System.out.println(si.x); 20 | 21 | NestedInner ni = c4.new NestedInner(); 22 | System.out.println(ni.y); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/Class05.java: -------------------------------------------------------------------------------- 1 | // tests basic subclassing 2 | class Base { 3 | } 4 | 5 | 6 | class Class05 extends Base { 7 | public static void main(String[] args) { 8 | System.out.println("extends"); 9 | } 10 | } -------------------------------------------------------------------------------- /test/Class06.java: -------------------------------------------------------------------------------- 1 | // tests basic class member lookup; python code changes 'x' to 'self.x' 2 | class Class06 { 3 | int x = 42; 4 | 5 | public void spam() { 6 | x += 1; 7 | System.out.println( x ); 8 | }; 9 | 10 | public static void main(String[] args) { 11 | Class06 c = new Class06(); 12 | c.spam(); 13 | } 14 | } -------------------------------------------------------------------------------- /test/Class07.java: -------------------------------------------------------------------------------- 1 | class Class07 { 2 | static int a = 1; 3 | private static int b = 2; 4 | private int c; 5 | 6 | private void x() { 7 | System.out.println('x'); 8 | } 9 | 10 | private void y() { 11 | System.out.println(a); 12 | } 13 | 14 | private void empty() { 15 | } 16 | 17 | private void z(int a) { 18 | System.out.println(a); 19 | } 20 | public static void main(String[] args) { 21 | System.out.println(a); 22 | System.out.println(b); 23 | 24 | Class07 c = new Class07(); 25 | c.x(); 26 | c.y(); 27 | c.z(3); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/Class08.java: -------------------------------------------------------------------------------- 1 | class Class08 { 2 | public int one() { 3 | return 1; 4 | } 5 | 6 | public void two(int a) { 7 | if (a>0) { 8 | return; 9 | } 10 | System.out.println(3); 11 | } 12 | 13 | public static void main(String[] args) { 14 | Class08 fm = new Class08(); 15 | System.out.println(fm.one()); 16 | fm.two(123); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Class09.java: -------------------------------------------------------------------------------- 1 | class Class09 { 2 | class Inner { 3 | void check() { 4 | System.out.println(42); 5 | } 6 | } 7 | 8 | public static void main(String[] args) { 9 | Class09 outer = new Class09(); 10 | Inner i = outer.new Inner(); 11 | i.check(); 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /test/Class10.java: -------------------------------------------------------------------------------- 1 | interface Base { 2 | int move(int dx, int dy); 3 | } 4 | 5 | interface Extra { 6 | } 7 | 8 | 9 | class Class10 implements Base, Extra { 10 | public int move(int dx, int dy) { 11 | return 0; 12 | } 13 | 14 | public void other(Class10 v) { 15 | } 16 | 17 | public void other() { 18 | } 19 | 20 | public static void main(String[] args) { 21 | Class10 i = new Class10(); 22 | System.out.println(i.getClass().getName()); 23 | 24 | for (Class c : i.getClass().getInterfaces()) { 25 | System.out.println(c.getName()); 26 | } 27 | } 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /test/Class11.java: -------------------------------------------------------------------------------- 1 | class Class11 { 2 | Integer x = 0; 3 | 4 | String any() { 5 | return x.toString(); 6 | } 7 | 8 | public static void main(String[] args) { 9 | Class11 c = new Class11(); 10 | System.out.println( c.any() ); 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /test/Class12.java: -------------------------------------------------------------------------------- 1 | class Class12 { 2 | private int c = 12; 3 | 4 | private void x() { 5 | System.out.println('x'); 6 | } 7 | 8 | public static void main(String[] args) { 9 | Class12 c = new Class12(); 10 | c.x(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Class13.java: -------------------------------------------------------------------------------- 1 | public class Class13 { 2 | 3 | static int x = 0; 4 | static int y = Class13.x; 5 | 6 | Class klass = Class13.class; 7 | 8 | public static void main(String[] args) { 9 | System.out.println(Class13.x == Class13.y ? 1 : 0); 10 | } 11 | 12 | } -------------------------------------------------------------------------------- /test/Comments0.java: -------------------------------------------------------------------------------- 1 | class Comments0 { 2 | 3 | static void bar(int x) { 4 | System.out.println(x); 5 | } 6 | public static void main(String[] args) { 7 | int foo = 2; 8 | while (foo > 0 /* what magic is this */) { 9 | bar(/* funk */ foo); 10 | foo -= 1; 11 | } 12 | bar(1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Comments1.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | multiline comment above the Comments class. 4 | 5 | **/ 6 | 7 | // single line comment above the Comments class. 8 | 9 | class Comments1 { 10 | /** multi above other method **/ 11 | // single above other method 12 | public static void other() { int j = 1;} 13 | 14 | /** multi above main method **/ 15 | // single above main method 16 | public static void main(String[] args) { 17 | /** multi inside the main method 18 | 19 | **/ 20 | // single line comment inside the main method 21 | int /** expr 1 **/ i = /** expr 2 **/ 1 /** expr 3 **/; /** expr 4 **/ // expr 5 22 | // skeaky 1 23 | } // skeaky 2 24 | // skeaky 3 25 | } // skeaky 4 26 | // skeaky 5 27 | -------------------------------------------------------------------------------- /test/Comments2.java: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | multiline comment above the Comments class. 4 | 5 | **/ 6 | 7 | 8 | 9 | class Comments2 { 10 | // single line comment below the Comments class. 11 | int x = 1; 12 | 13 | /** multi above other method **/ 14 | public static void other() { 15 | // single inside other method 16 | } 17 | 18 | public static void main(String[] args) { 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /test/Comments3.java: -------------------------------------------------------------------------------- 1 | class Comments3 { 2 | 3 | static void bar(int x) { 4 | System.out.println(x); 5 | } 6 | public static void main(String[] args) { 7 | int foo = 100; 8 | if (foo < 38) { 9 | // will never happen 10 | bar(/* funk */ 0); 11 | } 12 | bar(1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Comments4.java: -------------------------------------------------------------------------------- 1 | // Header Comment 2 | 3 | class Comments4 { 4 | void method() { 5 | for (;;) { } 6 | } 7 | 8 | public static void main(String[] args) { 9 | System.out.println("Comments4."); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /test/Continue0.java: -------------------------------------------------------------------------------- 1 | class Continue0 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | while (x < 10) { 5 | System.out.println(x); 6 | if (x == 6) { 7 | break; 8 | } else { 9 | x += 2; 10 | continue; 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Continue1.java: -------------------------------------------------------------------------------- 1 | class Continue1 { 2 | public static void main(String[] args) { 3 | int[] ints = {1, 2, 3, 4, 5, 6, 7}; 4 | for (int x : ints) { 5 | if (x == 6) { 6 | break; 7 | } else if (x == 3) { 8 | continue; 9 | } 10 | System.out.println(x); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/Continue2.java: -------------------------------------------------------------------------------- 1 | class Continue2 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | do { 5 | System.out.println(x); 6 | if (x == 6) { 7 | break; 8 | } else { 9 | x += 2; 10 | continue; 11 | } 12 | } while (x < 10); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Ctor0.java: -------------------------------------------------------------------------------- 1 | class Ctor0 { 2 | 3 | public int m_foo; 4 | public int m_bar; 5 | 6 | 7 | 8 | public Ctor0() { 9 | this(/* foo */ 0, /* bar */ 0); 10 | } 11 | 12 | public Ctor0(int p_foo) { 13 | this(p_foo, 0); 14 | 15 | } 16 | 17 | public Ctor0(int p_foo, int p_bar) { 18 | m_foo = p_foo; 19 | m_bar = p_bar; 20 | } 21 | 22 | 23 | public static void main(String[] args) { 24 | Ctor0 a = new Ctor0(); 25 | System.out.println(a.m_foo); 26 | System.out.println(a.m_bar); 27 | 28 | Ctor0 b = new Ctor0(1); 29 | System.out.println(b.m_foo); 30 | System.out.println(b.m_bar); 31 | 32 | 33 | Ctor0 c = new Ctor0(2, 3); 34 | System.out.println(c.m_foo); 35 | System.out.println(c.m_bar); 36 | 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /test/Ctor1.java: -------------------------------------------------------------------------------- 1 | class Ctor1 { 2 | 3 | public Ctor1() { 4 | System.out.println("Ctor1()"); 5 | } 6 | 7 | public Ctor1(int arg) { 8 | System.out.println("Ctor1(int)"); 9 | } 10 | 11 | public Ctor1(String arg) { 12 | System.out.println("Ctor1(String)"); 13 | } 14 | 15 | public static void main(String[] args) { 16 | Ctor1 t1 = new Ctor1(); 17 | Ctor1 t2 = new Ctor1(3); 18 | Ctor1 t3 = new Ctor1("notnull"); 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /test/Ctor2.java: -------------------------------------------------------------------------------- 1 | class Ctor2 { 2 | public int x = 1; 3 | public String y = null; 4 | 5 | public Ctor2() { 6 | x = 2; 7 | } 8 | 9 | public Ctor2(int arg) { 10 | x = arg; 11 | } 12 | 13 | public Ctor2(String arg) { 14 | y = arg; 15 | } 16 | 17 | public static void main(String[] args) { 18 | Ctor2 t1 = new Ctor2(); 19 | System.out.println(t1.x); 20 | 21 | Ctor2 t2 = new Ctor2(3); 22 | System.out.println(t2.x); 23 | 24 | Ctor2 t3 = new Ctor2("notnull"); 25 | System.out.println(t3.x); 26 | System.out.println(t3.y); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/Ctor3.java: -------------------------------------------------------------------------------- 1 | class Base { 2 | public int x = 42; 3 | public String y = null; 4 | 5 | public Base() { 6 | x = 43; 7 | } 8 | 9 | public Base(String arg) { 10 | y = arg; 11 | } 12 | 13 | public Base(int arg) { 14 | x = arg; 15 | } 16 | } 17 | 18 | class Test1 extends Base { 19 | public Test1() { 20 | } 21 | } 22 | 23 | 24 | class Test2 extends Base { 25 | public Test2() { 26 | super(); 27 | } 28 | } 29 | 30 | 31 | class Test3 extends Base { 32 | public Test3() { 33 | super("arg"); 34 | } 35 | } 36 | 37 | 38 | class Test4 extends Base { 39 | public Test4(int arg) { 40 | super(arg); 41 | } 42 | } 43 | 44 | 45 | public class Ctor3 { 46 | public static void main(String[] args) { 47 | Test1 t1 = new Test1(); 48 | System.out.println(43 == t1.x ? 1 : 0); 49 | 50 | Test2 t2 = new Test2(); 51 | System.out.println(43 == t2.x ? 1 : 0); 52 | 53 | Test3 t3 = new Test3(); 54 | System.out.println("arg" == t3.y ? 1 : 0); 55 | System.out.println(42 == t3.x ? 1 : 0); 56 | 57 | Test4 t4 = new Test4(10); 58 | System.out.println(10 == t4.x ? 1 :0); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /test/DoWhile0.java: -------------------------------------------------------------------------------- 1 | class DoWhile0 { 2 | public static void main(String[] args) { 3 | int x = 10; 4 | do { 5 | System.out.println(x); 6 | x++; 7 | } while (x<10); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/DoWhile1.java: -------------------------------------------------------------------------------- 1 | class DoWhile1 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | do { 5 | System.out.println(x); 6 | x++; 7 | } while (x<10); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Enum0.java: -------------------------------------------------------------------------------- 1 | enum Color { 2 | WHITE(10, 11+3), 3 | GRAY(20, 22), 4 | BLACK(30, 33); 5 | private final int val; 6 | 7 | Color(int v, int x) { 8 | this.val = v; 9 | } 10 | 11 | public int code() { 12 | return val; 13 | } 14 | } 15 | 16 | class Enum0 { 17 | public static void main(String[] args) { 18 | System.out.println(Color.WHITE.code()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/Enum1.java: -------------------------------------------------------------------------------- 1 | enum Day { 2 | SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; 3 | } 4 | 5 | class Enum1 { 6 | public static void main(String[] args) { 7 | System.out.println(Day.SUNDAY); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Exception0.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | 3 | class Exception0 { 4 | static void test() throws IOException { 5 | throw new IOException("test"); 6 | } 7 | 8 | public static void main(String[] args) { 9 | try { 10 | test(); 11 | } catch (IOException e) { 12 | System.out.println("catch"); 13 | } finally { 14 | System.out.println("done"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Expr0.java: -------------------------------------------------------------------------------- 1 | class Expr0 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | if (x++ == 0) { 5 | System.out.println(x); 6 | } 7 | System.out.println(x); 8 | 9 | 10 | int y = 0; 11 | if (++y == 1) { 12 | System.out.println(y); 13 | } 14 | System.out.println(y); 15 | 16 | 17 | int z = 0; 18 | if (--z == -1) { 19 | System.out.println(z); 20 | } 21 | System.out.println(z); 22 | 23 | 24 | int w = 0; 25 | if (w-- == 0) { 26 | System.out.println(w); 27 | } 28 | System.out.println(w); 29 | 30 | 31 | for (int i = 0; i<3; ++i) { 32 | System.out.println(i); 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/Expr1.java: -------------------------------------------------------------------------------- 1 | class Expr1 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | System.out.println(x); 5 | 6 | // assign 7 | x = 42; 8 | System.out.println(x); 9 | 10 | // plus assign 11 | x += 33; 12 | System.out.println(x); 13 | 14 | // minus assign 15 | x -= 21; 16 | System.out.println(x); 17 | 18 | // star assign 19 | x *= 17; 20 | System.out.println(x); 21 | 22 | // div assign 23 | x /= 4; 24 | System.out.println(x); 25 | 26 | // and assign 27 | x &= 3; 28 | System.out.println(x); 29 | 30 | 31 | // and assign 32 | x = 444; 33 | x &= 0x0bc; 34 | System.out.println(x); 35 | 36 | // or assign 37 | x = 444; 38 | x |= 0x01; 39 | System.out.println(x); 40 | 41 | // mod assign 42 | x = 13; 43 | x %= 5; 44 | System.out.println(x); 45 | 46 | 47 | // bit shift right assign 48 | // shift right assign 49 | // shift left assign 50 | 51 | // question 52 | x = 3; 53 | System.out.println(x==3 ? 1 : 0); 54 | System.out.println(x!=3 ? 1 : 0); 55 | 56 | 57 | String y = new String(); 58 | System.out.println(y instanceof String ? "object" : "notobject"); 59 | System.out.println(x <= 0 ? 1 : 0); 60 | System.out.println(x >= 0 ? 1 : 0); 61 | 62 | 63 | // logical or 64 | System.out.println(1 < 3 || 3 > 1 ? 1 : 0); 65 | 66 | // logical and 67 | System.out.println(1 < 3 && 3 > 1 ? 1 : 0); 68 | 69 | 70 | 71 | // or 72 | System.out.println(4 | 2); 73 | 74 | // xor 75 | System.out.println(4 ^ 3); 76 | 77 | // and 78 | System.out.println(3 & 2); 79 | 80 | 81 | // equal 82 | System.out.println(3 == 3 ? 1 : 0); 83 | System.out.println(3 == 4 ? 1 : 0); 84 | 85 | // not equal 86 | System.out.println(3 != 3 ? 1 : 0); 87 | System.out.println(3 != 4 ? 1 : 0); 88 | 89 | 90 | 91 | System.out.println(44 >> 3); 92 | System.out.println(44 > 3 ? 1 : 0); 93 | System.out.println(44 << 3); 94 | System.out.println(44 < 3 ? 1 : 0); 95 | 96 | 97 | x = 33; 98 | System.out.println(x+1); 99 | System.out.println(x-1); 100 | System.out.println(x*x*x); 101 | System.out.println(x/2); 102 | System.out.println(x%2); 103 | 104 | 105 | 106 | x = -33; 107 | System.out.println(-x); 108 | System.out.println(+x); 109 | 110 | 111 | 112 | // NB: these tests side-step the issue of using pre/post inc in 113 | // expressions 114 | x = 55; 115 | ++x; 116 | System.out.println(x); 117 | --x; 118 | System.out.println(x); 119 | x++; 120 | System.out.println(x); 121 | x--; 122 | System.out.println(x); 123 | 124 | 125 | x = 55; 126 | System.out.println(~x); 127 | 128 | System.out.println(!false ? 1 : 0); 129 | 130 | System.out.println( (Integer) x ); 131 | 132 | 133 | x = 7; 134 | System.out.println(x >>> 1); 135 | 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /test/Expr2.java: -------------------------------------------------------------------------------- 1 | class Expr2 { 2 | public static void main(String[] args) { 3 | int a = 1; 4 | int b = 2; 5 | int c = 3; 6 | int radius = 4; 7 | int y = (radius*radius*a*(a + radius)*radius*b*b) / (c*c+a*a+b*b); 8 | System.out.println(y); 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/ForEach0.java: -------------------------------------------------------------------------------- 1 | class ForEach0 { 2 | public static void main(String[] args) { 3 | int ints[] = {1, 2, 3, 4}; 4 | for (int i: ints) { 5 | System.out.println(i); 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/ForLoop0.java: -------------------------------------------------------------------------------- 1 | class ForLoop0 { 2 | public static void main(String[] args) { 3 | int ints[] = {1, 2, 3, 4}; 4 | for (int i = 0; i < 3; i++) { 5 | System.out.println(i); 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/ForLoop1.java: -------------------------------------------------------------------------------- 1 | class ForLoop1 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | for (;;) { 5 | if (x==2) { break; } 6 | System.out.println(x); 7 | x += 1; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/ForLoop2.java: -------------------------------------------------------------------------------- 1 | class ForLoop2 { 2 | public static void main(String[] args) { 3 | for (int i = 0; i < 3; i++) { 4 | if (i == 1) 5 | continue; 6 | System.out.println(i); 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Format0.java: -------------------------------------------------------------------------------- 1 | public class Format0 { 2 | public static void main(String[] args) { 3 | int i = 22; 4 | String s = "text"; 5 | String r = String.format("> (%1$d) %n %2$s", i, s); 6 | 7 | System.out.println(r); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Format1.java: -------------------------------------------------------------------------------- 1 | public class Format1 { 2 | public static void main(String[] args) { 3 | long n = 461012; 4 | String f1 = String.format("%d%n", n); // --> "461012" 5 | String f2 = String.format("%08d%n", n); // --> "00461012" 6 | String f3 = String.format("%+8d%n", n); // --> " +461012" 7 | String f4 = String.format("%,8d%n", n); // --> " 461,012" 8 | String f5 = String.format("%+,8d%n", n); // --> "+461,012" 9 | 10 | System.out.println(f1 + f2 + f3 + f4 + f5); 11 | 12 | double pi = 3.14159265; 13 | String pf1 = String.format("%f%n", pi); // --> "3.141593" 14 | String pf2 = String.format("%.3f%n", pi); // --> "3.142" 15 | String pf3 = String.format("%10.3f%n", pi); // --> " 3.142" 16 | 17 | System.out.println(pf1 + pf2 + pf3); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/GenericPairs0.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | class Pair{ 4 | private final T first; 5 | private final S second; 6 | 7 | public Pair(T f, S s) { 8 | first = f; 9 | second = s; 10 | } 11 | 12 | public T getFirst() { 13 | return first; 14 | } 15 | 16 | public S getSecond() { 17 | return second; 18 | } 19 | 20 | public String toString() { 21 | return "(" + first.toString() + ", " + second.toString() + ")"; 22 | } 23 | 24 | 25 | } 26 | 27 | 28 | 29 | class GenericPairs0 { 30 | 31 | public void printLines(List strings) { 32 | for (String s: strings) { 33 | System.out.println( s ); 34 | } 35 | } 36 | 37 | public void printObjects(List objects) { 38 | for (Object s: objects) { 39 | System.out.println( s ); 40 | } 41 | } 42 | 43 | 44 | 45 | public static void main(String[] args) { 46 | Pair first = new Pair("hello", "world"); 47 | System.out.println( first.toString() ); 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/If0.java: -------------------------------------------------------------------------------- 1 | class If0 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | 5 | if (x == 0) { 6 | System.out.println(0); 7 | } 8 | 9 | if (x == 0) { 10 | System.out.println(1); 11 | } else { 12 | System.out.println("fail"); 13 | } 14 | 15 | if (x == 0) { 16 | System.out.println(2); 17 | } else if (x == 1) { 18 | System.out.println("catastrophe"); 19 | } else if (x == 2) { 20 | System.out.println("error"); 21 | } else { 22 | System.out.println("disaster"); 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/If1.java: -------------------------------------------------------------------------------- 1 | class If1 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | if (x == 0) { 5 | System.out.println(1); 6 | } 7 | 8 | if (x == 1) { 9 | System.out.println(1); 10 | System.out.println(2); 11 | } else { 12 | System.out.println(0); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/If2.java: -------------------------------------------------------------------------------- 1 | class If2 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | 5 | if (x == 0) 6 | System.out.println(0); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/If3.java: -------------------------------------------------------------------------------- 1 | class If3 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | 5 | if (x == 1) 6 | System.out.println(0); 7 | else 8 | System.out.println(1); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/If4.java: -------------------------------------------------------------------------------- 1 | class If4 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | 5 | if (x == 1) 6 | System.out.println(1); 7 | else if (x == 2) 8 | System.out.println(2); 9 | else if (x == 3) 10 | System.out.println(3); 11 | else 12 | System.out.println(0); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/If5.java: -------------------------------------------------------------------------------- 1 | class If5 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | System.out.println(x); 5 | if (x == 0) 6 | return; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/If6.java: -------------------------------------------------------------------------------- 1 | class If6 { 2 | public static void main(String[] args) { 3 | if (false) { 4 | System.out.println("fail"); 5 | } else if (true) { 6 | System.out.println("okay"); 7 | } 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /test/If7.java: -------------------------------------------------------------------------------- 1 | class If7 { 2 | public static void main(String[] args) { 3 | if (false) { 4 | System.out.println("fail 1"); 5 | } else if (false) { 6 | System.out.println("fail 2"); 7 | } else { 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /test/If8.java: -------------------------------------------------------------------------------- 1 | class If8 { 2 | public static void main(String[] args) { 3 | if (true) { 4 | int y = 1; 5 | System.out.println(0 + y); 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/Interface0.java: -------------------------------------------------------------------------------- 1 | interface B0 { 2 | public void m(int x); 3 | } 4 | 5 | interface B1 { 6 | public void m(int x); 7 | } 8 | 9 | 10 | interface C0 extends B0, B1 { 11 | public void n(int y); 12 | } 13 | 14 | 15 | class Nothing {}; 16 | 17 | class Interface0 implements C0 { 18 | public void m(int x) { 19 | System.out.println(x); 20 | } 21 | 22 | public void n(int y) { 23 | System.out.println(y); 24 | } 25 | 26 | public static void main(String[] args) { 27 | Interface0 i = new Interface0(); 28 | i.m(0); 29 | i.n(1); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/Interface1.java: -------------------------------------------------------------------------------- 1 | interface I0 { 2 | public int m(int x); 3 | } 4 | 5 | 6 | class Interface1 implements I0 { 7 | public int m(int y) { 8 | return y; 9 | } 10 | 11 | public static void main(String[] args) { 12 | Interface1 i = new Interface1(); 13 | System.out.println(i.m(3)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Interface2.java: -------------------------------------------------------------------------------- 1 | interface Eggs { 2 | public void bar(int x); 3 | } 4 | 5 | 6 | interface Ham extends Eggs { 7 | public void baz(int y); 8 | } 9 | 10 | 11 | class Interface2 implements Ham { 12 | public void bar(int x) { 13 | System.out.println(x); 14 | } 15 | 16 | public void baz(int y) { 17 | System.out.println(y); 18 | } 19 | 20 | public static void main(String[] args) { 21 | Interface2 d = new Interface2(); 22 | d.bar(0); 23 | d.baz(1); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/JavaDoc0.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Class documentation in Java Doc format. 3 | * 4 | * @see some class docs 5 | */ 6 | class JavaDoc0 { 7 | /** 8 | * Method documentation in Java Doc format. 9 | * 10 | * @param bar an integer 11 | * @return some integer 12 | * @see someting else 13 | */ 14 | public int foo(int bar) { 15 | // before return comment 16 | return bar; 17 | // after return comment 18 | } 19 | 20 | public static void main(String[] args) { 21 | System.out.println(0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/Keywords0.java: -------------------------------------------------------------------------------- 1 | public class Keywords0 { 2 | public static void main(String[] args) { 3 | 4 | String and = "this is and"; 5 | System.out.println(and == "this is and" ? 1 : 0); 6 | 7 | String del = "this is del"; 8 | System.out.println(del == "this is del" ? 1 : 0); 9 | 10 | String elif = "this is elif"; 11 | System.out.println(elif == "this is elif" ? 1 : 0); 12 | 13 | String from = "this is from"; 14 | System.out.println(from == "this is from" ? 1 : 0); 15 | 16 | String in = "this is in"; 17 | System.out.println(in == "this is in" ? 1 : 0); 18 | 19 | String is = "this is is"; 20 | System.out.println(is == "this is is" ? 1 : 0); 21 | 22 | String not = "this is not"; 23 | System.out.println(not == "this is not" ? 1 : 0); 24 | 25 | String or = "this is or"; 26 | System.out.println(or == "this is or" ? 1 : 0); 27 | 28 | String print = "this is print"; 29 | System.out.println(print == "this is print" ? 1 : 0); 30 | 31 | String str = "this is str"; 32 | System.out.println(str == "this is str" ? 1 : 0); 33 | 34 | String None = "this is None"; 35 | System.out.println(None == "this is None" ? 1 : 0); 36 | 37 | String bool = "this is bool"; 38 | System.out.println(bool == "this is bool" ? 1 : 0); 39 | 40 | String True = "this is True"; 41 | System.out.println(True == "this is True" ? 1 : 0); 42 | 43 | String False = "this is False"; 44 | System.out.println(False == "this is False" ? 1 : 0); 45 | 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /test/Length0.java: -------------------------------------------------------------------------------- 1 | class Length0 { 2 | public static int dummy(int v) { 3 | return v + 1; 4 | } 5 | 6 | public static void main(String[] args) { 7 | String foo = "asdf"; 8 | System.out.println( dummy(foo.length() ) ); 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /test/Literals0.java: -------------------------------------------------------------------------------- 1 | class Literals0 { 2 | public static void main (String [] args) { 3 | 4 | int h = 0xAA; 5 | int o = 034; 6 | float f = .3f; 7 | double d = .4d; 8 | long l = 234l; 9 | char c = 'c'; 10 | String s = "string theory"; 11 | Boolean F = false; 12 | Boolean T = true; 13 | 14 | Object n = null; 15 | 16 | System.out.println(h); 17 | System.out.println(o); 18 | System.out.println(f); 19 | System.out.println(d); 20 | System.out.println(l); 21 | System.out.println(c); 22 | System.out.println(s); 23 | System.out.println(T ? 1 : 0); 24 | System.out.println(F ? 1 : 0); 25 | 26 | System.out.println(n==null ? 1 : 0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | javac := javac 2 | java := java 3 | python := python -B 4 | j2py = ../bin/j2py 5 | 6 | 7 | python_files := $(addsuffix .py, $(notdir $(basename $(wildcard *.java)))) 8 | test_targets := $(sort $(notdir $(basename $(wildcard *.java)))) 9 | 10 | export PYTHONPATH := $(PYTHONPATH):.:.. 11 | 12 | 13 | .PHONY: all clean 14 | .SILENT: %: 15 | 16 | 17 | all: 18 | $(MAKE) $(test_targets) 19 | 20 | 21 | selectors: 22 | @cd selector && make 23 | 24 | 25 | clean: 26 | @rm -f *.class *.pyc $(python_files) 27 | 28 | 29 | packages: 30 | @cd Package0 && javac Class0.java 31 | @cd Package0 && ../$(j2py) Class0.java Class0.py 32 | 33 | 34 | parsers: 35 | @cd ../java2python/lang && make -s 36 | 37 | 38 | %.class: 39 | [ -s $(addsuffix .java, $(basename $@)) ] && $(javac) $(addsuffix .java, $(basename $@)) 40 | 41 | 42 | %.py: %.class 43 | @$(j2py) $(addsuffix .java, $(basename $@)) $@ -c configs.defaults -d configs 44 | 45 | %: %.py 46 | @bash -c "diff -u <($(python) $(addsuffix .py, $@)) <(java -ea $@)" && echo "[PASS] $@" 47 | -------------------------------------------------------------------------------- /test/Math0.java: -------------------------------------------------------------------------------- 1 | class Math0 { 2 | public static void main(String[] args) { 3 | System.out.println(Math.abs(-42)); 4 | System.out.println(Math.abs(-0.5)); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Package0/Class0.java: -------------------------------------------------------------------------------- 1 | package Package0; 2 | 3 | public class Class0 { 4 | public int m() { 5 | return 42; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/Package0/Class0.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ generated source for module Class0 3 | 4 | """ 5 | # package: Package0 6 | class Class0(object): 7 | """ generated source for class Class0 8 | 9 | """ 10 | def m(self): 11 | """ generated source for method m 12 | 13 | """ 14 | return 42 15 | 16 | -------------------------------------------------------------------------------- /test/Package0/__init__.py: -------------------------------------------------------------------------------- 1 | from pkgutil import extend_path 2 | __path__ = extend_path(__path__, __name__) 3 | 4 | from Class0 import Class0 5 | -------------------------------------------------------------------------------- /test/Property0.java: -------------------------------------------------------------------------------- 1 | class Property0 { 2 | int m_bar = 0; 3 | 4 | public int barProp() { 5 | return m_bar; 6 | } 7 | 8 | public void barProp(int f) { 9 | m_bar = f; 10 | } 11 | 12 | public void barProp(String g) { 13 | 14 | } 15 | 16 | public static void main(String[] args) { 17 | Property0 p = new Property0(); 18 | System.out.println(p.barProp()); 19 | p.barProp(1); 20 | System.out.println(p.barProp()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/Property1.java: -------------------------------------------------------------------------------- 1 | class Property1 { 2 | int m_foo = 0; 3 | 4 | public int fooProp() { 5 | return m_foo; 6 | } 7 | 8 | public void fooProp(int f) { 9 | m_foo = f; 10 | } 11 | public static void main(String[] args) { 12 | Property1 p = new Property1(); 13 | System.out.println(p.fooProp()); 14 | p.fooProp(1); 15 | System.out.println(p.fooProp()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Self0.java: -------------------------------------------------------------------------------- 1 | class Self0 { 2 | private int v1 = 100; 3 | public int v2 = 2; 4 | 5 | public int test0(){ 6 | return v2 + v1; 7 | } 8 | 9 | public boolean test1(){ 10 | return (v1 == v2 || v2 < v1 ); 11 | } 12 | 13 | public static void main(String[] args) { 14 | Self0 s = new Self0(); 15 | System.out.println(s.test0()); 16 | if(s.test1()) 17 | System.out.println("True"); 18 | else 19 | System.out.println("False"); 20 | System.out.print("test"); 21 | System.out.print("ing"); 22 | System.out.println(); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /test/String0.java: -------------------------------------------------------------------------------- 1 | class String0 { 2 | static void test(String s) { 3 | System.out.println(s); 4 | } 5 | 6 | public static void main(String[] args) { 7 | test(String.valueOf(42)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Super0.java: -------------------------------------------------------------------------------- 1 | class Base { 2 | public int foo(int x) { 3 | return x + 1; 4 | } 5 | } 6 | 7 | class Super0 extends Base { 8 | 9 | public int foo(int y) { 10 | int retval = super.foo(y); 11 | return retval + 1; 12 | } 13 | 14 | public static void main(String[] args) { 15 | 16 | Super0 x = new Super0(); 17 | 18 | System.out.println(x.foo(3)); 19 | 20 | 21 | } 22 | 23 | 24 | } -------------------------------------------------------------------------------- /test/Switch0.java: -------------------------------------------------------------------------------- 1 | class Switch0 { 2 | 3 | public static void main(String[] args) { 4 | int x = 0; 5 | 6 | switch (x) { 7 | case 0: 8 | if (x==0) { 9 | System.out.println(x); 10 | break; 11 | } 12 | } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Switch1.java: -------------------------------------------------------------------------------- 1 | class Switch1 { 2 | public static void main(String[] args) { 3 | int x = 1; 4 | switch (x) { 5 | case 0: 6 | } 7 | System.out.println(x); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Switch2.java: -------------------------------------------------------------------------------- 1 | class Switch2 { 2 | public static void main(String[] args) { 3 | int x = 1; 4 | int y = 0; 5 | switch (x) { 6 | default: 7 | y = 4; 8 | break; 9 | } 10 | System.out.println(y); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Switch3.java: -------------------------------------------------------------------------------- 1 | class Switch3 { 2 | public static void main(String[] args) { 3 | int x = 1; 4 | int y = 0; 5 | switch (x) { 6 | case 1: 7 | y = 1; 8 | break; 9 | case 2: 10 | y = 2; 11 | break; 12 | case 3: 13 | y = 3; 14 | break; 15 | default: 16 | y = 4; 17 | break; 18 | } 19 | System.out.println(y); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/Switch4.java: -------------------------------------------------------------------------------- 1 | class Switch4 { 2 | public static void main(String[] args) { 3 | int x = 1; 4 | switch (x) { 5 | // empty switch 6 | } 7 | System.out.println(x); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Switch5.java: -------------------------------------------------------------------------------- 1 | // tests switches with class attributes 2 | 3 | class Switch5 { 4 | public static final int RT_VOLUME = 48; 5 | 6 | public static String getField( int val) { 7 | switch( val) { 8 | case RT_VOLUME: return "rt volume"; 9 | default: return "unknown"; 10 | 11 | } 12 | } 13 | 14 | public static void main(String[] args) { 15 | Switch5 c = new Switch5(); 16 | System.out.println( c.getField(48) ); 17 | System.out.println( c.getField(49) ); 18 | } 19 | 20 | 21 | } -------------------------------------------------------------------------------- /test/Synchronized0.java: -------------------------------------------------------------------------------- 1 | class Synchronized0 { 2 | private long c1 = 0; 3 | private long c2 = 0; 4 | private Object lock1 = new Object(); 5 | private Object lock2 = new Object(); 6 | 7 | 8 | public void inc1() { 9 | synchronized(lock1) { 10 | c1++; 11 | } 12 | } 13 | 14 | public void inc2() { 15 | synchronized(lock1) { 16 | c2++; 17 | } 18 | } 19 | 20 | public static void main(String[] args) { 21 | Synchronized0 obj = new Synchronized0(); 22 | obj.inc1(); 23 | obj.inc2(); 24 | System.out.println( obj.c1 ); 25 | System.out.println( obj.c2 ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/Synchronized1.java: -------------------------------------------------------------------------------- 1 | class Synchronized1 { 2 | 3 | public synchronized void run() { 4 | System.out.println(0); 5 | } 6 | 7 | public static synchronized void class_run() { 8 | System.out.println(0); 9 | } 10 | 11 | public static void main(String[] args) { 12 | Synchronized1 obj = new Synchronized1(); 13 | obj.run(); 14 | obj.class_run(); 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Synchronized2.java: -------------------------------------------------------------------------------- 1 | class Synchronized2 { 2 | 3 | public synchronized void test1() { 4 | System.out.println(1); 5 | } 6 | 7 | public synchronized void test1(String s) { 8 | System.out.println(s); 9 | } 10 | 11 | public static synchronized void test1(int i) { 12 | System.out.println(i); 13 | } 14 | 15 | public static synchronized void test2() { 16 | System.out.println(2); 17 | } 18 | 19 | public static synchronized void test2(String s) { 20 | System.out.println(s); 21 | } 22 | 23 | public synchronized void test2(int i) { 24 | System.out.println(i); 25 | } 26 | 27 | public static void main(String[] args) { 28 | Synchronized2 obj = new Synchronized2(); 29 | obj.test1(); 30 | obj.test1("test1"); 31 | obj.test1(1); 32 | obj.test2(); 33 | obj.test2("test2"); 34 | obj.test2(2); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/Ternary0.java: -------------------------------------------------------------------------------- 1 | final class Ternary0 extends Object { 2 | public static void main(String[] args) { 3 | System.out.println(1 > 0 ? 'a' : 'b'); 4 | System.out.println(1 == 0 ? 'a' : 'b'); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Throw0.java: -------------------------------------------------------------------------------- 1 | class Throw0 { 2 | public static void main(String[] args) { 3 | try { 4 | throw new Exception("some exception message"); 5 | } catch (Exception e) { 6 | System.out.println( "caught" ); 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Try0.java: -------------------------------------------------------------------------------- 1 | class Try0 { 2 | 3 | public static void main(String[] args) { 4 | try { 5 | System.out.println(0); 6 | } catch (Exception e) { 7 | } 8 | 9 | 10 | try { 11 | System.out.println(1); 12 | } catch (Exception e) { 13 | System.out.println(2); 14 | } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/TypeTransform0.java: -------------------------------------------------------------------------------- 1 | class TypeTransform0 { 2 | public boolean b; 3 | public double d; 4 | 5 | public static void main(String[] args) {} 6 | } -------------------------------------------------------------------------------- /test/UsePackage0.java: -------------------------------------------------------------------------------- 1 | import Package0.*; 2 | 3 | class UsePackage0 { 4 | public static void main(String[] args) { 5 | Package0.Class0 c = new Package0.Class0(); 6 | System.out.println( c.m() ); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/VariadicMethod0.java: -------------------------------------------------------------------------------- 1 | class VariadicMethod0 { 2 | 3 | public static void show(Object... objects) { 4 | for (Object o : objects) 5 | System.out.println(o.toString() + " "); 6 | } 7 | public static void main(String[] args) { 8 | VariadicMethod0.show(0+0, 1, 2, "three", .5f); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/VoidClass0.java: -------------------------------------------------------------------------------- 1 | 2 | class VoidClass0 { 3 | 4 | public static void main(String[] args) { 5 | Class x = void.class; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/While0.java: -------------------------------------------------------------------------------- 1 | class While0 { 2 | public static void main(String[] args) { 3 | int x = 10; 4 | while (x>10) { 5 | } 6 | System.out.println("ok"); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/While1.java: -------------------------------------------------------------------------------- 1 | class While1 { 2 | public static void main(String[] args) { 3 | int x = 0; 4 | while (x<10) { 5 | System.out.println(x); 6 | x++; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/While2.java: -------------------------------------------------------------------------------- 1 | class While2 { 2 | public static void main(String[] args) { 3 | int x = 10; 4 | while (x<10) { 5 | System.out.println(x); 6 | x++; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/altconfigs/Class10.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natural/java2python/b8037561c542522ae620e0a071ecc7e668461587/test/altconfigs/Class10.py -------------------------------------------------------------------------------- /test/configs/Cast0.py: -------------------------------------------------------------------------------- 1 | from java2python.mod import basic 2 | 3 | expressionCastHandler = basic.castDrop 4 | -------------------------------------------------------------------------------- /test/configs/Class00.py: -------------------------------------------------------------------------------- 1 | modulePrologueHandlers = [] 2 | moduleEpilogueHandlers = [] 3 | -------------------------------------------------------------------------------- /test/configs/Class10.py: -------------------------------------------------------------------------------- 1 | modulePrologueHandlers = [ 2 | 'from java2python.mod.include.overloading import overloaded', 3 | ] 4 | -------------------------------------------------------------------------------- /test/configs/GenericPairs0.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from java2python.config import default 4 | 5 | 6 | moduleOutputSubs = default.moduleOutputSubs + [ 7 | (r'import java\.util', r''), 8 | (r'first\ \=\ T\(\)', 'first = None'), 9 | (r'second\ \=\ S\(\)', 'second = None'), 10 | ] 11 | -------------------------------------------------------------------------------- /test/configs/Interface3.py: -------------------------------------------------------------------------------- 1 | ## 2 | # This is an example of how to perform per-module configuration 3 | # for translating java interfaces to zope interfaces. 4 | # 5 | from java2python.mod import basic 6 | from java2python.config import default 7 | 8 | 9 | # the j2py default head handlers for interfaces includes ABCMeta as a 10 | # metaclass. we certainly don't want that, so we redefine the list 11 | # here to only the doc string handler: 12 | interfaceHeadHandlers = [ 13 | basic.simpleDocString, 14 | ] 15 | 16 | 17 | # this j2py default is also not what we want, so we redefine it: 18 | methodPrologueHandlers = [ 19 | basic.maybeClassMethod, 20 | ] 21 | 22 | 23 | # instead of the default bases, this handler supplies the base zope 24 | # Interface class for Java interfaces: 25 | interfaceBaseHandlers = [ 26 | basic.zopeInterfaceBases, 27 | ] 28 | 29 | 30 | # the parser adds implemented interfaces to the class bases list. 31 | # this handler checks to see if any of those bases are interfaces, and 32 | # if so, supresses them in favor of 'object' as the only base: 33 | classBaseHandlers = [ 34 | basic.zopeImplementsClassBases, 35 | ] 36 | 37 | 38 | # this handler adds a line like "zope.interface.implements(IFoo)" for 39 | # each interface implemented by a Java class: 40 | classHeadHandlers = [ 41 | basic.zopeImplementsClassHead, 42 | ] 43 | 44 | 45 | # this handler supresses the "self" parameter on method signatures for 46 | # zope Interface definitions: 47 | methodParamHandlers = [ 48 | basic.zopeInterfaceMethodParams, 49 | ] 50 | -------------------------------------------------------------------------------- /test/configs/UsePackage0.py: -------------------------------------------------------------------------------- 1 | from java2python.mod import basic 2 | 3 | moduleImportDeclarationHandler = basic.simpleImports 4 | -------------------------------------------------------------------------------- /test/configs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natural/java2python/b8037561c542522ae620e0a071ecc7e668461587/test/configs/__init__.py -------------------------------------------------------------------------------- /test/configs/defaults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | modulePrologueHandlers = [ 4 | 'from java2python.mod.include.classmethod import classmethod_ as classmethod', 5 | 'from java2python.mod.include.overloading import overloaded', 6 | 'import zope.interface', 7 | ] 8 | 9 | 10 | outputSubs = [ 11 | (r'(.*?)\.getMessage\(\)', r'\1.message'), 12 | (r'(.*?)(\w+?)\.length(.*)', r'\1len(\2)\3'), 13 | (r'assertEquals', 'self.assertEquals'), 14 | (r'## import junit.framework', 'from unittest import *'), 15 | (r'(.*?)\.getClass\(\)', r'\1.__class__'), 16 | (r'(.*?)\.getName\(\)', r'\1.__name__'), 17 | (r'(.*?)\.getInterfaces\(\)', r'\1.__bases__'), 18 | 19 | (r'(.*?)\.fooProp\(\)', r'\1.fooProp'), 20 | (r'(.*?)\.fooProp\((.+)\)', r'\1.fooProp = \2'), 21 | 22 | (r'(.*?)lock(.*?) = object\(\)', r'\1lock\2 = Lock()'), 23 | 24 | ## these two fudge something that should be handled in parsing 25 | (r'(.*?)StaticInner\(\)', r'\1cls.StaticInner()'), 26 | (r'(.*?)outer\.cls', r'\1outer'), 27 | (r'from java\.util import \*', ''), 28 | ] 29 | -------------------------------------------------------------------------------- /test/other_config_a.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natural/java2python/b8037561c542522ae620e0a071ecc7e668461587/test/other_config_a.py -------------------------------------------------------------------------------- /test/other_config_b.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natural/java2python/b8037561c542522ae620e0a071ecc7e668461587/test/other_config_b.py -------------------------------------------------------------------------------- /test/runj2py: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PYTHONPATH=$PYTHONPATH:.. ../bin/j2py -d configs "$@" 3 | -------------------------------------------------------------------------------- /test/runjava: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] 4 | then 5 | echo Usage: $0 file.java 6 | exit 1 7 | fi 8 | 9 | if [ -e "$1" ] 10 | then 11 | javac "$1" && java -ea `echo $1 | sed s/\.java//` && rm `echo $1 | sed s/\.java/\.class/` 12 | exit 0 13 | else 14 | echo File \""$1"\" does not exist. 15 | exit 2 16 | fi 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/selector/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | test_targets := $(sort $(notdir $(basename $(wildcard *.py)))) 4 | 5 | 6 | all: 7 | $(MAKE) $(test_targets) 8 | 9 | %: 10 | @python -m unittest -v $@ 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/selector/Selector1.java: -------------------------------------------------------------------------------- 1 | class Selector1 { 2 | void bar(int x, int y) { 3 | int foo = 3; 4 | String z = "foo"; 5 | } 6 | 7 | void foo() {}; 8 | 9 | } -------------------------------------------------------------------------------- /test/selector/test_all.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import sys 5 | import unittest 6 | 7 | from java2python.compiler import buildAST 8 | from java2python.lang import tokens 9 | from java2python.lang.selector import Token, Type 10 | from java2python.lib import colors 11 | 12 | 13 | def setUpModule(): 14 | fn = os.path.join(os.path.dirname(__file__), 'Selector1.java') 15 | SelectorTest.tree = buildAST(open(fn).read()) 16 | SelectorTest.tree.dump(sys.stdout) 17 | 18 | 19 | class SelectorTest(unittest.TestCase): 20 | def walk(self, selector): 21 | return list(selector.walk(self.tree)) 22 | 23 | def assertNodes(self, nodes, length): 24 | self.assertTrue(nodes) 25 | self.assertEqual(len(nodes), length) 26 | 27 | def shortDescription(self): 28 | fs = 'Description: {}\nSelector: {}\n' 29 | args = (colors.cyan(self.description), colors.yellow(self.selector)) 30 | return fs.format(*args) 31 | 32 | @classmethod 33 | def make(cls, count): 34 | def t(self): 35 | nodes = self.walk(self.selector) 36 | self.assertNodes(nodes, count) 37 | return t 38 | 39 | 40 | class TestIdentChildOfClass(SelectorTest): 41 | description = 'select one IDENT node that is a child of a CLASS node' 42 | selector = Type('CLASS') > Type('IDENT') 43 | test = SelectorTest.make(1) 44 | 45 | 46 | class TestIdentWithText(SelectorTest): 47 | description = 'select two IDENT nodes with text "foo"' 48 | selector = Type('IDENT', 'foo') 49 | test = SelectorTest.make(2) 50 | 51 | 52 | class TestTokensWithText(SelectorTest): 53 | description = 'select two nodes with text "foo"' 54 | selector = Token(text='foo') 55 | test = SelectorTest.make(2) 56 | 57 | 58 | class TestTokenCallableCombo(SelectorTest): 59 | description = 'select BLOCK_SCOPE on line 7' 60 | selector = Token(type=lambda t: t.type == tokens.BLOCK_SCOPE, line=7) 61 | test = SelectorTest.make(1) 62 | 63 | 64 | class TestTokenMultipleCallables(SelectorTest): 65 | description = 'select BLOCK_SCOPE on line 2 or 7' 66 | selector = Token(type=lambda t: t.type == tokens.BLOCK_SCOPE, line=lambda t:t.line in (2, 7)) 67 | test = SelectorTest.make(2) 68 | 69 | 70 | class TestTokenChildCallable(SelectorTest): 71 | description = 'select BLOCK_SCOPE with one child IDENT starting with "f"' 72 | selector = Token(type=lambda t: t.type == tokens.BLOCK_SCOPE) & Token(type='IDENT', text=lambda tok:tok.text.startswith('f')) 73 | test = SelectorTest.make(1) 74 | 75 | 76 | class TestNthChildWithExtraChecks(SelectorTest): 77 | description = 'select two children of FORMAL_PARAM_STD_DECL at index 2 ' 78 | selector = Type('FORMAL_PARAM_STD_DECL')[2] 79 | 80 | def test(self): 81 | nodes = self.walk(self.selector) 82 | self.assertNodes(nodes, 2) 83 | self.assertEquals(nodes[0].type, tokens.IDENT) 84 | self.assertEquals(nodes[1].type, tokens.IDENT) 85 | self.assertEquals(nodes[0].text, 'x') 86 | self.assertEquals(nodes[1].text, 'y') 87 | 88 | 89 | class TestDirectChildren(SelectorTest): 90 | description = 'select two TYPE nodes that are children of a VAR_DECLARATION node' 91 | selector = Type('VAR_DECLARATION') > Type('TYPE') 92 | test = SelectorTest.make(2) 93 | 94 | 95 | class TestSimpleSiblings(SelectorTest): 96 | description = 'select three IDENT nodes that are adjacent siblings of a MODIFIER_LIST' 97 | selector = Type('MODIFIER_LIST') + Type('IDENT') 98 | test = SelectorTest.make(3) 99 | 100 | 101 | class TestSimpleAnySibling(SelectorTest): 102 | description = 'select three FORMAL_PARAM_LIST nodes that are non-adjacent siblings of a MODIFIER_LIST' 103 | selector = Type('MODIFIER_LIST') / Type('FORMAL_PARAM_LIST') 104 | test = SelectorTest.make(2) 105 | 106 | 107 | class TestClassIdent(SelectorTest): 108 | description = 'select one IDENT node that is a child of a CLASS node' 109 | selector = Type('CLASS') > Type('IDENT') 110 | test = SelectorTest.make(1) 111 | --------------------------------------------------------------------------------