Added:
/branches/0.5/test/Package1/__init__.py
/branches/0.5/test/UsePackage1.java
Deleted:
/branches/0.5/test/PackageUse1.java
Modified:
/branches/0.5/bin/j2py
/branches/0.5/doc/customization.rst
/branches/0.5/doc/features.rst
/branches/0.5/doc/index.rst
/branches/0.5/doc/intro.rst
/branches/0.5/doc/usage.rst
/branches/0.5/java2python/compiler/template.py
/branches/0.5/java2python/compiler/visitor.py
/branches/0.5/java2python/config/default.py
/branches/0.5/java2python/mod/basic.py
/branches/0.5/test/Makefile
/branches/0.5/test/Package1/Class1.java
/branches/0.5/test/runj2py
=======================================
--- /dev/null
+++ /branches/0.5/test/Package1/__init__.py Wed Jul 28 15:44:19 2010
@@ -0,0 +1,4 @@
+from pkgutil import extend_path
+__path__ = extend_path(__path__, __name__)
+
+from Class1 import Class1
=======================================
--- /dev/null
+++ /branches/0.5/test/UsePackage1.java Wed Jul 28 15:44:19 2010
@@ -0,0 +1,8 @@
+import Package1.*;
+
+class UsePackage1 {
+ public static void main(String[] args) {
+ Package1.Class1 c = new Package1.Class1();
+ System.out.println( c.m() );
+ }
+}
=======================================
--- /branches/0.5/test/PackageUse1.java Wed Jul 28 01:49:35 2010
+++ /dev/null
@@ -1,8 +0,0 @@
-import Package1.*;
-
-class PackageUse1 {
- public static void main(String[] args) {
- Package1.Class1 c = new Package1.Class1();
- System.out.println( c.m() );
- }
-}
=======================================
--- /branches/0.5/bin/j2py Mon Jul 26 18:14:27 2010
+++ /branches/0.5/bin/j2py Wed Jul 28 15:44:19 2010
@@ -5,7 +5,7 @@
from collections import defaultdict
from logging import _levelNames as logLevels, exception, warning, info,
basicConfig
from optparse import Option, OptionParser, OptionValueError
-from os.path import basename, splitext
+from os import path
from time import time
from java2python.compiler import Module, buildAST, transformAST
@@ -45,7 +45,7 @@
TYPE_CHECKER['loglevel'] = checkLogLevel
-def profileMain(options):
+def mainProfile(options):
if options.profile:
import cProfile, pstats
prof = cProfile.Profile()
@@ -58,21 +58,30 @@
return main(options)
+def configFromDir(inname, dirname):
+ name = path.join(dirname, path.basename(path.splitext(inname)[0]))
+ return '%s.py' % path.abspath(name)
+
+
def main(options):
timed = defaultdict(time)
timed['overall']
- configs = options.configs
- if options.includedefaults:
- configs.insert(0, 'java2python.config.default')
-
filein = fileout = filedefault = '-'
if options.inputfile and not isinstance(options.inputfile, file):
filein = options.inputfile
if options.outputfile and not isinstance(options.outputfile, file):
- fileout = basename(options.outputfile)
+ fileout = path.basename(options.outputfile)
elif fileout != filedefault:
- fileout = '%s.py' % (splitext(filein)[0])
+ fileout = '%s.py' % (path.splitext(filein)[0])
+
+ configs = options.configs
+ if options.configdir and not isinstance(filein, file):
+ dirconfigname = configFromDir(filein, options.configdir)
+ if path.exists(dirconfigname):
+ configs.insert(0, dirconfigname)
+ if options.includedefaults:
+ configs.insert(0, 'java2python.config.default')
try:
if filein != '-':
@@ -99,7 +108,8 @@
timed['visit']
module = Module(config)
- module.name = splitext(basename(filein))[0] if filein != '-'
else '<stdin>'
+ module.sourceFilename = path.abspath(filein) if filein != '-' else None
+ module.name = path.splitext(path.basename(filein))[0] if filein != '-'
else '<stdin>'
module.walk(tree)
timed['visit_finish']
@@ -121,7 +131,7 @@
output = sys.stdout
else:
output = open(fileout, 'w')
- module.name = splitext(filein)[0] if filein != '-' else '<stdin>'
+ module.name = path.splitext(filein)[0] if filein != '-' else '<stdin>'
print >> output, source
try:
@@ -140,40 +150,43 @@
def config(argv):
- parser = OptionParser(option_class=LocalOption,
- version='%prog ' + version)
- parser.add_option('-i', '--input', dest='inputfile',
- help='Read from INPUTFILE. May use - for stdin.',
- metavar='INPUTFILE', default=None)
- parser.add_option('-o', '--output', dest='outputfile',
- help='Write to OUTPUTFILE. May use - for stdout.',
- metavar='OUTPUTFILE', default=None)
- parser.add_option('-c', '--config', dest='configs',
- help='Use CONFIG file or module. May be repeated.',
- metavar='CONFIG', default=[],
- action='append')
- parser.add_option('-n', '--nodefaults', dest='includedefaults',
- help='Ignore default configuration module.',
- default=True, action='store_false')
- parser.add_option('-l', '--loglevel', dest='loglevel',
- help='Set log level by name or value.',
- default='WARN', type='loglevel')
- parser.add_option('-p', '--python-tree', dest='pytree',
- help='Print python object tree to stderr.',
- default=False, action='store_true')
- parser.add_option('-j', '--java-ast', dest='javaast',
- help='Print java source AST tree to stderr.',
- default=False, action='store_true')
- parser.add_option('-f', '--profile', dest='profile',
- help='Profile execution and print results to stderr.',
- default=False, action='store_true')
- parser.add_option('-s', '--skip-source', dest='skipsource',
- help='Skip writing translated source; useful when printing trees',
- default=False, action='store_true')
- parser.add_option('-r', '--nocolor', dest='nocolor',
- help='Disable color output.' +\
- (' No effect on Win OS.' if isWindows() else ''),
- default=False, action='store_true')
+ parser = OptionParser(option_class=LocalOption,
version='%prog '+version)
+ addopt = parser.add_option
+ addopt('-i', '--input', dest='inputfile',
+ help='Read from INPUTFILE. May use - for stdin.',
+ metavar='INPUTFILE', default=None)
+ addopt('-o', '--output', dest='outputfile',
+ help='Write to OUTPUTFILE. May use - for stdout.',
+ metavar='OUTPUTFILE', default=None)
+ addopt('-c', '--config', dest='configs',
+ help='Use CONFIG file or module. May be repeated.',
+ metavar='CONFIG', default=[],
+ action='append')
+ addopt('-d', '--configdir', dest='configdir',
+ help='Use DIR to match input filename with config filename.',
+ metavar='DIR', default=None)
+ addopt('-n', '--nodefaults', dest='includedefaults',
+ help='Ignore default configuration module.',
+ default=True, action='store_false')
+ addopt('-l', '--loglevel', dest='loglevel',
+ help='Set log level by name or value.',
+ default='WARN', type='loglevel')
+ addopt('-p', '--python-tree', dest='pytree',
+ help='Print python object tree to stderr.',
+ default=False, action='store_true')
+ addopt('-j', '--java-ast', dest='javaast',
+ help='Print java source AST tree to stderr.',
+ default=False, action='store_true')
+ addopt('-f', '--profile', dest='profile',
+ help='Profile execution and print results to stderr.',
+ default=False, action='store_true')
+ addopt('-s', '--skip-source', dest='skipsource',
+ help='Skip writing translated source; useful when printing trees',
+ default=False, action='store_true')
+ addopt('-r', '--nocolor', dest='nocolor',
+ help='Disable color output.' +\
+ (' No effect on Win OS.' if isWindows() else ''),
+ default=False, action='store_true')
options, args = parser.parse_args(argv)
if len(args) > 2:
@@ -194,4 +207,4 @@
if __name__ == '__main__':
- sys.exit(profileMain(config(sys.argv)))
+ sys.exit(mainProfile(config(sys.argv)))
=======================================
--- /branches/0.5/doc/customization.rst Mon Jul 26 18:14:27 2010
+++ /branches/0.5/doc/customization.rst Wed Jul 28 15:44:19 2010
@@ -8,7 +8,13 @@
basic and advanced... wouldn't it be great?
-Advanced Customization
-----------------------
+Advanced or Not-So-Basic Customization
+--------------------------------------
There are two ways to further customize the behavior of |j2py|.
+
+
+Advanced Advanced but It's-Still-Not-Hard Customization
+-------------------------------------------------------
+
+Truly?
=======================================
--- /branches/0.5/doc/features.rst Mon Jul 26 18:14:27 2010
+++ /branches/0.5/doc/features.rst Wed Jul 28 15:44:19 2010
@@ -6,9 +6,9 @@
The |j2py| package can translate any syntactically valid Java source
code file. The generated Python code is not guaranteed to run, nor is
-guaranteed to be valid syntatically valid Python. However, |j2py|
-works well many cases, and in some of those, it creates perfectly
-usable and workable Python code.
+guaranteed to be syntatically valid Python. However, |j2py| works
+well many cases, and in some of those, it creates perfectly usable and
+workable Python code.
The remainder of this chapter describes how Java language features are
translated into Python constructs.
@@ -18,10 +18,10 @@
================
The approach taken by |j2py| is to favor readability over correctness
-for two reasons: first, it is quite rare that Java source code will
-work correctly without modification because of semantic and run-time
-differences, and second, |j2py| is meant to aid in one-time and
-ongoing translation projects.
+for two reasons: first, it is quite rare to find Java source code that
+will can be translated directly to Python without modification because
+of semantic and run-time differences, and second, |j2py| is meant to
+aid in one-time and ongoing translation projects.
What Works Well (Unless You Try Really Hard to Break It)
@@ -39,3 +39,512 @@
A (Mostly) Complete List
=========================
+The following list is an edited version of the grammar presented in
+JLS3. The list has been edited for clarity and conciseness and |j2py|
+support for each construct is noted as well.
+
+http://java.sun.com/docs/books/jls/third_edition/html/syntax.html
+
+
+
+
+
+
+ * ``Identifier: IDENTIFIER``
+
+ |j2py| copies identifiers from source to target, modifying the value
only when:
+
+ * the identifier conflicts with a Python keyword or builtin, or
+ * the identifier has an explicit lexical transformation
+
+ * ``QualifiedIdentifier: Identifier { . Identifier }``
+
+ Same behavior as Identifier; each value is examined and transformed
individullly
+
+ * ``Literal: IntegerLiteral | FloatingPointLiteral | CharacterLiteral |
StringLiteral | BooleanLiteral | NullLiteral``
+
+ Literals are copied from source to target with the following
modifications:
+
+ * ``null`` is changed to ``None``
+ * ``false`` is changed to ``False``
+ * ``true`` is changed to ``True``
+ * if necessary, floating point literals are modified to become valid
Python values
+ * string and character literals are translated as Python strings
+
+ Transformation of literal values happens at the AST level; see the
+ ``astTransforms`` configuration value for details.
+
+ * ``Expression: Expression1 [AssignmentOperator Expression1]]``
+
+ Refer to the individual expression types below.
+
+ * ``AssignmentOperator:
+ =
+ +=
+ -=
+ *=
+ /=
+ &=
+ |=
+ ^=
+ %=
+ <<=
+ >>=
+ >>>=
+ ``
+
+
+Type:
+ Identifier [TypeArguments]{ . Identifier [TypeArguments]} {[]}
+ BasicType
+
+TypeArguments:
+ < TypeArgument {, TypeArgument} >
+
+TypeArgument:
+ Type
+ ? [( extends |super ) Type]
+
+StatementExpression:
+ Expression
+
+ConstantExpression:
+ Expression
+
+Expression1:
+ Expression2 [Expression1Rest]
+
+Expression1Rest:
+ ? Expression : Expression1
+
+Expression2 :
+ Expression3 [Expression2Rest]
+
+Expression2Rest:
+ {InfixOp Expression3}
+ Expression3 instanceof Type
+
+InfixOp:
+ ||
+ &&
+ |
+ ^
+ &
+ ==
+ !=
+ <
+ >
+ <=
+ >=
+ <<
+ >>
+ >>>
+ +
+ -
+ *
+ /
+ %
+
+Expression3:
+ PrefixOp Expression3
+ ( Expression | Type ) Expression3
+ Primary {Selector} {PostfixOp}
+
+Primary:
+ ParExpression
+ NonWildcardTypeArguments (ExplicitGenericInvocationSuffix | this
+Arguments)
+ this [Arguments]
+ super SuperSuffix
+ Literal
+ new Creator
+ Identifier { . Identifier }[ IdentifierSuffix]
+ BasicType {[]} .class
+ void.class
+
+IdentifierSuffix:
+ [ ( ] {[]} . class | Expression ])
+ Arguments
+ . ( class | ExplicitGenericInvocation | this | super Arguments |
new
+[NonWildcardTypeArguments] InnerCreator )
+
+ExplicitGenericInvocation:
+ NonWildcardTypeArguments ExplicitGenericInvocationSuffix
+
+NonWildcardTypeArguments:
+ < TypeList >
+
+
+ExplicitGenericInvocationSuffix:
+ super SuperSuffix
+ Identifier Arguments
+
+
+PrefixOp:
+ ++
+ --
+ !
+ ~
+ +
+ -
+
+PostfixOp:
+ ++
+ --
+
+Selector: Selector:
+ . Identifier [Arguments]
+ . ExplicitGenericInvocation
+ . this
+ . super SuperSuffix
+ . new [NonWildcardTypeArguments] InnerCreator
+ [ Expression ]
+
+SuperSuffix:
+ Arguments
+ . Identifier [Arguments]
+
+BasicType:
+ byte
+ short
+ char
+ int
+ long
+ float
+ double
+ boolean
+
+Arguments:
+ ( [Expression { , Expression }] )
+
+Creator:
+ [NonWildcardTypeArguments] CreatedName ( ArrayCreatorRest |
+ClassCreatorRest )
+
+CreatedName:
+ Identifier [NonWildcardTypeArguments] {. Identifier
+[NonWildcardTypeArguments]}
+
+InnerCreator:
+ Identifier ClassCreatorRest
+
+ArrayCreatorRest:
+ [ ( ] {[]} ArrayInitializer | Expression ] {[ Expression ]} {[]} )
+
+ClassCreatorRest:
+ Arguments [ClassBody]
+
+ArrayInitializer:
+ { [VariableInitializer {, VariableInitializer} [,]] }
+
+VariableInitializer:
+ ArrayInitializer
+ Expression
+
+ParExpression:
+ ( Expression )
+
+Block:
+ { BlockStatements }
+
+BlockStatements:
+ { BlockStatement }
+
+BlockStatement :
+ LocalVariableDeclarationStatement
+ ClassOrInterfaceDeclaration
+ [Identifier :] Statement
+
+LocalVariableDeclarationStatement:
+ [final] Type VariableDeclarators ;
+
+Statement:
+ Block
+ assert Expression [ : Expression] ;
+ if ParExpression Statement [else Statement]
+ for ( ForControl ) Statement
+ while ParExpression Statement
+ do Statement while ParExpression ;
+ try Block ( Catches | [Catches] finally Block )
+ switch ParExpression { SwitchBlockStatementGroups }
+ synchronized ParExpression Block
+ return [Expression] ;
+ throw Expression ;
+ break [Identifier]
+ continue [Identifier]
+ ;
+ StatementExpression ;
+ Identifier : Statement
+
+Catches:
+ CatchClause {CatchClause}
+
+CatchClause:
+ catch ( FormalParameter ) Block
+
+SwitchBlockStatementGroups:
+ { SwitchBlockStatementGroup }
+
+SwitchBlockStatementGroup:
+ SwitchLabel BlockStatements
+
+SwitchLabel:
+ case ConstantExpression :
+ case EnumConstantName :
+ default :
+
+MoreStatementExpressions:
+ { , StatementExpression }
+
+ForControl:
+ ForVarControl
+ ForInit; [Expression] ; [ForUpdate]
+
+ForVarControl
+ [final] [Annotations] Type Identifier ForVarControlRest
+
+Annotations:
+ Annotation [Annotations]
+
+Annotation:
+ @ TypeName [( [Identifier =] ElementValue)]
+
+ElementValue:
+ ConditionalExpression
+ Annotation
+ ElementValueArrayInitializer
+
+ConditionalExpression:
+ Expression2 Expression1Rest
+
+ ElementValueArrayInitializer:
+ { [ElementValues] [,] }
+
+ ElementValues:
+ ElementValue [ElementValues]
+
+ForVarControlRest:
+ VariableDeclaratorsRest; [Expression] ; [ForUpdate]
+ : Expression
+
+ForInit:
+ StatementExpression Expressions
+
+Modifier:
+ Annotation
+ public
+ protected
+ private
+ static
+ abstract
+ final
+ native
+ synchronized
+ transient
+ volatile
+ strictfp
+
+VariableDeclarators:
+ VariableDeclarator { , VariableDeclarator }
+
+VariableDeclaratorsRest:
+ VariableDeclaratorRest { , VariableDeclarator }
+
+ConstantDeclaratorsRest:
+ ConstantDeclaratorRest { , ConstantDeclarator }
+
+VariableDeclarator:
+ Identifier VariableDeclaratorRest
+
+ConstantDeclarator:
+ Identifier ConstantDeclaratorRest
+
+VariableDeclaratorRest:
+ {[]} [ = VariableInitializer]
+
+ConstantDeclaratorRest:
+ {[]} = VariableInitializer
+
+VariableDeclaratorId:
+ Identifier {[]}
+
+CompilationUnit:
+ [[Annotations] package QualifiedIdentifier ; ]
{ImportDeclaration}
+{TypeDeclaration}
+
+ImportDeclaration:
+ import [ static] Identifier { . Identifier } [ . * ] ;
+
+TypeDeclaration:
+ ClassOrInterfaceDeclaration
+ ;
+
+ClassOrInterfaceDeclaration:
+ {Modifier} (ClassDeclaration | InterfaceDeclaration)
+
+ClassDeclaration:
+ NormalClassDeclaration
+ EnumDeclaration
+
+NormalClassDeclaration:
+ class Identifier [TypeParameters] [extends Type] [implements TypeList]
+ClassBody
+
+TypeParameters:
+ < TypeParameter {, TypeParameter} >
+
+TypeParameter:
+ Identifier [extends Bound]
+
+Bound:
+ Type {& Type}
+
+
+EnumDeclaration:
+ enum Identifier [implements TypeList] EnumBody
+
+EnumBody:
+ { [EnumConstants] [,] [EnumBodyDeclarations] }
+
+EnumConstants:
+ EnumConstant
+ EnumConstants , EnumConstant
+
+EnumConstant:
+ Annotations Identifier [Arguments] [ClassBody]
+
+EnumBodyDeclarations:
+ ; {ClassBodyDeclaration}
+
+InterfaceDeclaration:
+ NormalInterfaceDeclaration
+ AnnotationTypeDeclaration
+
+NormalInterfaceDeclaration:
+ interface Identifier [ TypeParameters] [extends TypeList]
InterfaceBody
+
+TypeList:
+ Type { , Type}
+
+AnnotationTypeDeclaration:
+ @ interface Identifier AnnotationTypeBody
+
+ AnnotationTypeBody:
+ { [AnnotationTypeElementDeclarations] }
+
+ AnnotationTypeElementDeclarations:
+ AnnotationTypeElementDeclaration
+ AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration
+
+AnnotationTypeElementDeclaration:
+ {Modifier} AnnotationTypeElementRest
+
+AnnotationTypeElementRest:
+ Type Identifier AnnotationMethodOrConstantRest;
+ ClassDeclaration
+ InterfaceDeclaration
+ EnumDeclaration
+ AnnotationTypeDeclaration
+
+ AnnotationMethodOrConstantRest:
+ AnnotationMethodRest
+ AnnotationConstantRest
+
+AnnotationMethodRest:
+ ( ) [DefaultValue]
+
+AnnotationConstantRest:
+ VariableDeclarators
+
+
+ DefaultValue:
+ default ElementValue
+
+ClassBody:
+ { {ClassBodyDeclaration} }
+
+InterfaceBody:
+ { {InterfaceBodyDeclaration} }
+
+ClassBodyDeclaration:
+ ;
+ [static] Block
+ {Modifier} MemberDecl
+
+MemberDecl:
+ GenericMethodOrConstructorDecl
+ MethodOrFieldDecl
+ void Identifier VoidMethodDeclaratorRest
+ Identifier ConstructorDeclaratorRest
+ InterfaceDeclaration
+ ClassDeclaration
+
+GenericMethodOrConstructorDecl:
+ TypeParameters GenericMethodOrConstructorRest
+
+GenericMethodOrConstructorRest:
+ (Type | void) Identifier MethodDeclaratorRest
+ Identifier ConstructorDeclaratorRest
+
+MethodOrFieldDecl:
+ Type Identifier MethodOrFieldRest
+
+MethodOrFieldRest:
+ VariableDeclaratorRest
+ MethodDeclaratorRest
+
+InterfaceBodyDeclaration:
+ ;
+ {Modifier} InterfaceMemberDecl
+
+InterfaceMemberDecl:
+ InterfaceMethodOrFieldDecl
+ InterfaceGenericMethodDecl
+ void Identifier VoidInterfaceMethodDeclaratorRest
+ InterfaceDeclaration
+ ClassDeclaration
+
+InterfaceMethodOrFieldDecl:
+ Type Identifier InterfaceMethodOrFieldRest
+
+InterfaceMethodOrFieldRest:
+ ConstantDeclaratorsRest ;
+ InterfaceMethodDeclaratorRest
+
+MethodDeclaratorRest:
+ FormalParameters {[]} [throws QualifiedIdentifierList] (
MethodBody | ;
+)
+
+VoidMethodDeclaratorRest:
+ FormalParameters [throws QualifiedIdentifierList] ( MethodBody
| ; )
+
+InterfaceMethodDeclaratorRest:
+ FormalParameters {[]} [throws QualifiedIdentifierList] ;
+
+InterfaceGenericMethodDecl:
+ TypeParameters (Type | void) Identifier
InterfaceMethodDeclaratorRest
+
+VoidInterfaceMethodDeclaratorRest:
+ FormalParameters [throws QualifiedIdentifierList] ;
+
+ConstructorDeclaratorRest:
+ FormalParameters [throws QualifiedIdentifierList] MethodBody
+
+QualifiedIdentifierList:
+ QualifiedIdentifier { , QualifiedIdentifier}
+
+FormalParameters:
+ ( [FormalParameterDecls] )
+
+FormalParameterDecls:
+ [final] [Annotations] Type FormalParameterDeclsRest]
+
+FormalParameterDeclsRest:
+ VariableDeclaratorId [ , FormalParameterDecls]
+ ... VariableDeclaratorId
+
+MethodBody:
+ Block
+
+EnumConstantName:
+ Identifier
=======================================
--- /branches/0.5/doc/index.rst Mon Jul 26 18:14:27 2010
+++ /branches/0.5/doc/index.rst Wed Jul 28 15:44:19 2010
@@ -3,11 +3,17 @@
You can adapt this file completely to your liking, but it should at
least
contain the root `toctree` directive.
-java2python |release| Documentation
+|j2py| |release| Documentation
===================================
Welcome! This is the documentation for java2python |release|, last
updated |today|.
+Please read the :ref:`intro` for information what the package
+does, how it works, and why it was created. From there, you should
+proceed to the :ref:`usage` chapter for an overview of how to work
+with the tool. When you really get going, you'll want to read the
+:ref:`features` chapter to learn what you can do.
+
Contents:
@@ -16,8 +22,8 @@
:numbered:
intro.rst
- features.rst
usage.rst
+ features.rst
customization.rst
=======================================
--- /branches/0.5/doc/intro.rst Mon Jul 26 18:14:27 2010
+++ /branches/0.5/doc/intro.rst Wed Jul 28 15:44:19 2010
@@ -1,9 +1,107 @@
.. _intro:
+************
Introduction
+************
+
+What it Does
============
-wah wah wah
-
-it's like a pedal.
-
+|j2py| reads the Java source files you give it and produces
+somewhat-roughly-equivalent Python source code. It tries to make the
+same decisions you would if you were porting the code manually. It
+can perform the translation faster and more accuratly than you could,
+because it's a dumb machine that does what its told and you're a smart
+person with lots of books you haven't read and a love of chocolate so
+sometimes you're easily distracted and make mistakes. Like me and
+this documentation.
+
+Where It's Useful
+=================
+
+|j2py| can help in two situations. First, if you're doing a one-time
+port of a Java project to Python, it can save you a lot of time and
+effort by getting you really far really fast.
+
+Second, if you've got a Java project and you'd like to generate a
+Python port and keep the port up to date, you'll find that |j2py| can
+help tremendously. The per-project and per-file configuration system
+helps out a lot in this area.
+
+Where |j2py| is not useful is also important. It won't be useful to
+you if you expect your newly translated Python code to run correctly
+the first time. The platforms are too different and this tool is too
+limited for that to happen. Also, you won't find |j2py| very useful
+if you expect to convert Java sources at runtime, but that's really a
+special case of the former.
+
+
+How it Works
+=============
+
+|j2py| first converts the source code you give it into an abstract
+syntax tree. (That's a lie, really. |j2py| doesn't do this step,
+Antlr does this step, and Antlr is a whole lot bigger and cooler than
+|j2py| could ever be. Obviously, really smart people worked on Antlr
+and only one fairly dim one worked on |j2py|).
+
+After the syntax tree is constructed, it's walked and its nodes are
+converted to their Python equivalents. When the walking is complete,
+|j2py| takes a few more swipes at it and prints it out. It's all very
+boring, like geology or watching someone learn to play the flute.
+
+This is all well and good for most cases where there exists a very
+similar Python construct for the given Java construct. Classes, for
+example, are pretty much the same in both languages. The trouble
+spots are places where a construct exists in Java that is not readily
+available in Python.
+
+Note: yes, of course, we're dealing with Turing Machines and they're
+equivalent. If it works in Java, it can work in Python, and I'm not
+saying that it can't. But what I am saying is that there are chunks
+of Java source code that you can't make into nice and neat and obvious
+Python equivalents.
+
+To get around these trouble spots, |j2py| takes one of two approaches
+(and sometimes both if she's feeling especially fiesty or if you
+haven't paid her much attention lately). The first approach is to try
+and make the problem go away. For example, in Java the `if` statement
+can contain an assigment expression::
+
+ if (++x == 0) { ... }
+
+There isn't a single statement equivalent in Python because assigments
+are statements there, not expressions. So |j2py| does what it can,
+presuably what you would do::
+
+ x += 1
+ if x == 0:
+ ...
+
+Careful readers will have spotted just how close we came to driving
+over a cliff with that `++x` expression. If the increment had been
+done on the other side of the variable, the meaning of the statement
+would have changed and the Python code would have been wrong.
+Fortuatly, I've driven by lots of cliffs and have been scared by all
+of them so I thought of this ahead of time and decided to do something
+about it::
+
+ if (x++ ==0) { ... }
+
+will get translated to::
+
+ mangled_name_for_x = x
+ x += 1
+ if mangled_name_for_x == 0:
+ ...
+
+See what |j2py| did there? It tried to do what you would do. For
+further explaination and enumeration see the :ref:`features` chapter.
+
+
+Why Bother?
+===========
+
+I bothered to write this because I needed a Java package to run on the
+CPython interpreter. I got tired of porting by hand, so I wrote this
+instead. And it's an interesting problem (kind of).
=======================================
--- /branches/0.5/doc/usage.rst Mon Jul 26 18:14:27 2010
+++ /branches/0.5/doc/usage.rst Wed Jul 28 15:44:19 2010
@@ -25,23 +25,23 @@
Options and Arguments
=====================
-The :command:`j2py` command accepts several options that control its
-behavior. To change code generation behavior, refer to the
-:ref:`customization` chapter.
+The :command:`j2py` command accepts options that alter its behavior.
+The behavior of the code generator is not part of the command itself;
+to change code generation behavior, refer to the :ref:`customization`
+chapter.
Code generation:
-
* .. option:: -i NAME, --input NAME
- Read from the specified file. Specify ``-`` for ``stdin``. If
- not given the command will read from ``stdin``.
+ Read from the given file. Specify ``-`` for ``stdin``. If not
+ given the command will read from ``stdin``.
* .. option:: -o NAME, --output NAME
- Write to the specified file. Specify ``-`` for ``stdout``. If
- not given the command will write to ``stdout``.
+ Write to the given file. Specify ``-`` for ``stdout``. If not
+ given the command will write to ``stdout``.
* .. option:: -l LEVEL, --loglevel LEVEL
@@ -54,10 +54,20 @@
Use the specified configuration module or file. This option may
be repeated.
- Configuration values are retrieved in reverse order, i.e., from
- the final value given to the first given, with the default
+ Configuration modules/files are referenced in reverse order, i.e.,
+ from the final value given to the first given, with the default
configuration referenced last.
+ See the :ref:`customization` chapter for details of the
+ configuration system and available configuration points.
+
+ * .. option:: -d DIR, --configdir DIR
+
+ Use the given directory name to match input filenames to
+ configuration filenames. For example, to translate
+ ``FooBar.java`` and use the configuration stored in
+ ``./cfg/FooBar.py``, specify ``-d ./cfg``.
+
* .. option:: -n, --nodefaults
Ignore the default configuration module.
@@ -71,7 +81,6 @@
Development:
-
* .. option:: -p, --python-tree
Print a representation of the internal Python code tree.
=======================================
--- /branches/0.5/java2python/compiler/template.py Mon Jul 26 18:14:27 2010
+++ /branches/0.5/java2python/compiler/template.py Wed Jul 28 15:44:19 2010
@@ -248,6 +248,12 @@
class BaseComment(BaseExpression):
""" BaseComment -> base class for formatting Python comments. """
+ def __init__(self, config, left='', right='', fs=FS.lr, parent=None,
tail=''):
+ super(BaseComment, self).__init__(config, left, right, fs, parent, tail)
+ if not fs.strip().startswith('#'):
+ prefix = self.config.last('commentPrefix', '# ')
+ self.fs = prefix + self.fs
+
def __repr__(self):
""" Returns the debug string representation of this comment. """
parts = [white(self.typeName+':'),
=======================================
--- /branches/0.5/java2python/compiler/visitor.py Mon Jul 26 18:14:27 2010
+++ /branches/0.5/java2python/compiler/visitor.py Wed Jul 28 15:44:19 2010
@@ -100,9 +100,24 @@
acceptEnum = makeAcceptType('enum')
acceptInterface = makeAcceptType('interface')
+
+
class Module(ModuleClassSharedMixin, Base):
""" Module -> accepts AST branches for module-level objects. """
+ def makeAcceptHandledDecl(part):
+ def accept(self, node, memo):
+ expr = self.factory.expr()
+ expr.walk(node.firstChild(), memo)
+ handler = self.configHandler(part)
+ if handler:
+ handler(self, expr)
+ return accept
+
+ acceptImport = makeAcceptHandledDecl('ImportDeclaration')
+ acceptPackage = makeAcceptHandledDecl('PackageDeclaration')
+
+
class ClassMethodSharedMixin(object):
def acceptModifierList(self, node, memo):
@@ -568,6 +583,10 @@
def acceptClassConstructorCall(self, node, memo):
""" Accept and process a class constructor call. """
self.acceptMethodCall(node, memo) # probably wrong
+ typeIdent = node.firstChildOfType(tokens.QUALIFIED_TYPE_IDENT)
+ if typeIdent and typeIdent.children:
+ ids = [self.altIdent(child.text) for child in typeIdent.children]
+ self.left = '.'.join(ids) # wrong
def acceptMethodCall(self, node, memo):
""" Accept and process a method call. """
=======================================
--- /branches/0.5/java2python/config/default.py Mon Jul 26 18:14:27 2010
+++ /branches/0.5/java2python/config/default.py Wed Jul 28 15:44:19 2010
@@ -28,9 +28,6 @@
modulePrologueHandlers = [
basic.simpleShebang,
basic.simpleDocString,
- basic.configImports,
- basic.commentedImports,
- basic.commentedPackageName,
basic.insertBsr,
]
@@ -106,6 +103,19 @@
expressionVariableNamingHandler = basic.globalNameCounter
+# This handler simply creates comments in the file for package
+# declarations.
+modulePackageDeclarationHandler = basic.commentedPackages
+
+# This handler can be used instead to create __init__.py files for
+# 'namespace packages' via pkgutil.
+modulePackageDeclarationHandler = basic.namespacePackages
+
+
+moduleImportDeclarationHandler = basic.commentedImports
+moduleImportDeclarationHandler = basic.simpleImports
+
+
# The AST transformation function uses these declarations to modify an
# AST before compiling it to python source. Having these declarations
# in a config file gives clients an opportunity to change the
=======================================
--- /branches/0.5/java2python/mod/basic.py Mon Jul 26 18:14:27 2010
+++ /branches/0.5/java2python/mod/basic.py Wed Jul 28 15:44:19 2010
@@ -1,6 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from itertools import count
+from logging import info, warn
+from os import path
from re import sub as rxsub
@@ -14,19 +16,32 @@
yield '"""'
-def configImports(module):
- if 0:
- yield ''
+def commentedImports(module, expr):
+ module.factory.comment(parent=module, left=expr, fs='import: {left}')
-def commentedImports(module):
- if 0:
- yield ''
-
-
-def commentedPackageName(module):
- if 0:
- yield ''
+def simpleImports(module, expr):
+ module.factory.expr(parent=module, left=expr, fs='import {left}')
+
+def commentedPackages(module, expr):
+ module.factory.comment(parent=module, left=expr, fs='package: {left}')
+
+
+def namespacePackages(module, expr):
+ source = module.sourceFilename
+ if not source:
+ warn('namespace package not created; source input not named.')
+ return
+ initname = path.join(path.dirname(source), '__init__.py')
+ if path.exists(initname):
+ warn('namespace package not created; __init__.py exists.')
+ return
+ with open(initname, 'w') as initfile:
+ initfile.write('from pkgutil import extend_path\n')
+ initfile.write('__path__ = extend_path(__path__, __name__)\n')
+ ## wrong
+ initfile.write('\nfrom {0} import {0}\n'.format(module.name))
+ info('created __init__.py file for package %s.', expr)
def enumConstInts(enum, index, name):
=======================================
--- /branches/0.5/test/Makefile Wed Jul 28 01:49:35 2010
+++ /branches/0.5/test/Makefile Wed Jul 28 15:44:19 2010
@@ -4,9 +4,8 @@
j2py = ../bin/j2py
-java_files := $(wildcard *.java)
-class_files := $(wildcard *.class)
python_files := $(addsuffix .py, $(notdir $(basename $(wildcard *.java))))
+test_targets := $(notdir $(basename $(wildcard *.java)))
.PHONY: all clean
@@ -14,7 +13,7 @@
all:
- @echo run something else for now
+ $(MAKE) $(test_targets)
clean:
@@ -39,5 +38,4 @@
%: %.py
- @bash -c "diff <($(python) $(addsuffix .py, $@)) <(java -ea $@)" &&
echo "[OKAY] $@"
-
+ @bash -c "diff -q <($(python) $(addsuffix .py, $@)) <(java -ea $@)" &&
echo "[PASS] $@"
=======================================
--- /branches/0.5/test/Package1/Class1.java Wed Jul 28 01:49:35 2010
+++ /branches/0.5/test/Package1/Class1.java Wed Jul 28 15:44:19 2010
@@ -1,4 +1,6 @@
-class Class1 {
+package Package1;
+
+public class Class1 {
public int m() {
return 42;
}
=======================================
--- /branches/0.5/test/runj2py Wed Jul 14 11:56:45 2010
+++ /branches/0.5/test/runj2py Wed Jul 28 15:44:19 2010
@@ -1,14 +1,2 @@
#!/bin/bash
-
-
-make parser &>/dev/null
-
-if [ $? -eq 0 ]
-then
- PYTHONPATH=$PYTHONPATH:..:. ../bin/j2py -c testconfig "$@"
-else
- echo make failed
-fi
-
-
-
+../bin/j2py -c configs "$@"