Created
February 7, 2014 01:00
-
-
Save tshirtman/8855677 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python | |
| ''' | |
| Usage: | |
| parse.py <path> <exportpath> <suffix> [<packagename>] | |
| parse.py --jar=<jarfile> <exportpath> [<packagename>] --suffix=<suffix> | |
| Options: | |
| path is the path to look java classes into | |
| exportpath is the destination dir to produce classes into | |
| packagename is an optional package name to put in the generated | |
| classe files | |
| -j --jar=<jarfile> used to look for classes in a jar instead of a path | |
| ''' | |
| # TODO | |
| # handling jars | |
| try: | |
| import plyj.parser as plyj | |
| import jinja2 | |
| from docopt import docopt | |
| except ImportError: | |
| print "please install plyj, jinja2 and docopt" | |
| exit() | |
| import os | |
| parser = plyj.Parser() | |
| env = jinja2.Environment() | |
| def get_type(ptype): | |
| """Get the string representing a type | |
| """ | |
| if isinstance(ptype, str): | |
| return ptype | |
| elif isinstance(ptype.name, str): | |
| return ptype.name | |
| else: | |
| return ptype.name.value | |
| def render_params(params): | |
| """A filter to display the parameters of a function call | |
| """ | |
| return ', '.join( | |
| '{type} {name}'.format( | |
| type=get_type(param.type), | |
| name=param.variable.name) | |
| for param in params) | |
| def render_params_values(params): | |
| return ', '.join( | |
| '{name}'.format( | |
| name=param.variable.name) | |
| for param in params) | |
| def import_types(module): | |
| """This gets all the imports done in the original module, not all of | |
| them are necessary, but it's easier this way | |
| """ | |
| for i in module.import_declarations: | |
| yield 'import %s;\n' % i.name.value | |
| env.filters['render_params'] = render_params | |
| env.filters['render_params_values'] = render_params_values | |
| env.filters['get_type'] = get_type | |
| class_template = env.from_string('''\ | |
| {% if package %}package {{ package }};{% endif %} | |
| import {{ module.package_declaration.name.value }}.*; | |
| {{ imports }}\ | |
| public class {{ cls.name }}{{ suffix }} extends {{ cls.name }} { | |
| public interface I{{ cls.name }} {\ | |
| {% for method in methods %} | |
| {{ method.return_type | get_type }} {{ method.name }}({{ method.parameters | render_params }});\ | |
| {% endfor %} | |
| } | |
| private I{{ cls.name }} implem = null; | |
| {% for method in methods %} | |
| {{ method.return_type | get_type }} {{ method.name }}({{ method.parameters | render_params }}) { | |
| if (this.implem) | |
| return this.implem.{{ method.name }}({{ method.parameters | render_params_values }}); | |
| }{% endfor %} | |
| } | |
| ''') | |
| def get_abstract_classes(path): | |
| """Being given a path, this function will return all the abstract | |
| classes defined in it | |
| """ | |
| for path, _, files in os.walk(path): | |
| for f in files: | |
| if f.endswith('.java'): | |
| j = parser.parse_file(file(os.path.join(path, f))) | |
| if j: | |
| for tp in j.type_declarations: | |
| if ( | |
| tp and 'public' in tp.modifiers and | |
| 'abstract' in tp.modifiers | |
| ): | |
| yield j, tp | |
| def get_abstract_methods(tp): | |
| """Given an abstract class, this will return all its abstract | |
| methods | |
| """ | |
| for member in tp.body: | |
| if ( | |
| isinstance(member, plyj.MethodDeclaration) and | |
| 'abstract' in member.modifiers | |
| ): | |
| yield member | |
| if __name__ == '__main__': | |
| arguments = docopt(__doc__) | |
| outpath = os.path.join( | |
| arguments['<exportpath>'], | |
| *arguments.get('<packagename>', '').split('.')) | |
| suffix = arguments.get('<suffix>', '') | |
| if not os.path.exists(outpath): | |
| os.makedirs(outpath) | |
| for module, cls in get_abstract_classes(arguments['<path>']): | |
| methods = list(get_abstract_methods(cls)) | |
| package = arguments.get('<packagename>') | |
| javaclass = class_template.render( | |
| package=package, | |
| imports=''.join(import_types(module)), | |
| module=module, | |
| suffix=suffix, | |
| cls=cls, | |
| methods=methods) | |
| with open('%s.java' % (os.path.join( | |
| outpath, cls.name + suffix)), 'w' | |
| ) as f: | |
| f.write(javaclass) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment