package org.autoplot.jythonsupport; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import org.autoplot.datasource.DataSetURI; import org.das2.jythoncompletion.JavadocLookup; import org.das2.util.LoggerManager; import org.das2.util.monitor.NullProgressMonitor; import org.python.core.PyFloat; import org.python.core.PyInteger; import org.python.parser.SimpleNode; import org.python.parser.ast.Assert; import org.python.parser.ast.Assign; import org.python.parser.ast.Attribute; import org.python.parser.ast.AugAssign; import org.python.parser.ast.BinOp; import org.python.parser.ast.BoolOp; import org.python.parser.ast.Break; import org.python.parser.ast.Call; import org.python.parser.ast.ClassDef; import org.python.parser.ast.Compare; import org.python.parser.ast.Continue; import org.python.parser.ast.Dict; import org.python.parser.ast.Expr; import org.python.parser.ast.ExtSlice; import org.python.parser.ast.For; import org.python.parser.ast.FunctionDef; import org.python.parser.ast.Global; import org.python.parser.ast.If; import org.python.parser.ast.Import; import org.python.parser.ast.ImportFrom; import org.python.parser.ast.Index; import org.python.parser.ast.ListComp; import org.python.parser.ast.Name; import org.python.parser.ast.Num; import org.python.parser.ast.Pass; import org.python.parser.ast.Print; import org.python.parser.ast.Raise; import org.python.parser.ast.Return; import org.python.parser.ast.Slice; import org.python.parser.ast.Str; import org.python.parser.ast.Subscript; import org.python.parser.ast.TryExcept; import org.python.parser.ast.Tuple; import org.python.parser.ast.UnaryOp; import org.python.parser.ast.VisitorBase; import org.python.parser.ast.While; import org.python.parser.ast.aliasType; import org.python.parser.ast.excepthandlerType; import org.python.parser.ast.exprType; import org.python.parser.ast.keywordType; import org.python.parser.ast.listcompType; import org.python.parser.ast.sliceType; import org.python.parser.ast.stmtType; /** * experiment with code which converts the Jython AST (syntax tree) into Java * code. See also https://cottagesystems.com/JavaJythonConverter/ which goes * the other way. * * @author jbf */ public class JythonToJavaConverter { private static final Logger logger= LoggerManager.getLogger("jython"); private static Map packages= null; public static String TYPE_INT="int"; public static String TYPE_FLOAT="float"; public static String TYPE_STRING="String"; public static String TYPE_STRING_ARRAY="String[]"; public static String TYPE_OBJECT="Object"; public static String TYPE_MAP="Map"; /** * scan through the list of imports in /importLookup.jy, to see * if the symbol can be imported. This will return null (None) if * there are no suggestions, or the name of the package. * @param clas the class name, for example "JSlider" * @return the package or null, for example "javax.swing" */ public synchronized static String guessPackage( String clas ) { if ( packages==null ) { try { Map lpackages=new HashMap<>(); try ( BufferedReader r = new BufferedReader( new InputStreamReader( JythonToJavaConverter.class.getResourceAsStream("/importLookup.jy") ) ) ) { String l; Pattern p= Pattern.compile("from (.*) import (.*)"); while ( (l= r.readLine() )!=null ) { if ( l.length()==0 ) continue; if ( l.charAt(0)=='#' ) continue; Matcher m= p.matcher(l); if ( m.matches() ) { lpackages.put( m.group(2),m.group(1) ); } else { logger.log(Level.INFO, "does not match pattern: {0}", l); } } } packages= lpackages; } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } } String result= packages.get(clas); if ( result==null ) { List sss= JavadocLookup.getInstance().searchForSignature(clas); for ( int i=0; i guessCompletions(String clas) { ArrayList result = new ArrayList<>(); try (BufferedReader r = new BufferedReader(new InputStreamReader( JythonToJavaConverter.class.getResourceAsStream("/importLookup.jy")))) { String l; Pattern p = Pattern.compile("from (.*) import (.*)"); while ((l = r.readLine()) != null) { if (l.length() == 0) { continue; } if (l.charAt(0) == '#') { continue; } Matcher m = p.matcher(l); if (m.matches()) { // here is the logic String tclas = m.group(2); if (tclas.startsWith(clas)) { result.add(tclas); } } else { logger.log(Level.INFO, "does not match pattern: {0}", l); } } } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } List sss= JavadocLookup.getInstance().searchForSignature(clas); for ( int i=0; i-1 ) { result.add(s.substring(idx+1)); } } return result; } /** * add the class to the list of imports. * @param doc the document * @param pkg the Java package * @param name the Java class name. */ public static void addImport( Document doc, String pkg, String name ) { addImport( doc, pkg, name, doc.getLength() ); } /** * add the class to the list of imports. * @param doc the document * @param pkg the Java package * @param name the Java class name. * @param cursorPosition the cursor position. */ public static void addImport( Document doc, String pkg, String name, int cursorPosition ) { try { String s= doc.getText( 0, cursorPosition ); String[] ss= s.split("\n"); Pattern p= Pattern.compile("from (.+) import (.*)"); boolean haveIt=false; int addToLine= -1; int addAtOffset= -1; int offset= 0; for ( int i=0; i-1 ) { doc.insertString( addAtOffset, ","+name, null ); } else { doc.insertString( 0, "from "+pkg+" import "+name + "\n", null ); } } } catch (BadLocationException ex) { Logger.getLogger(JythonToJavaConverter.class.getName()).log(Level.SEVERE, null, ex); } } /** * add the class to the list of imports. * @param src the Jython source * @param pkg the Java package * @param name the Java class name. * @return the new version of the script. */ public static String addImport( String src, String pkg, String name ) { String[] ss= src.split("\n"); Pattern p= Pattern.compile("from (.+) import (.*)"); boolean haveIt=false; int addToLine= -1; for ( int i=0; i-1 ) { ss[addToLine]= ss[addToLine]+","+name; return String.join("\n",ss); } else { return "from "+pkg+" import "+name + "\n" + String.join("\n",ss); } } else { return src; } } /** * return true if the class has been imported. Note this is not thorough * and should be reviewed at some point. * @param src the Jython source * @param pkg the Java package * @param name the Java class name. * @return true if the class has been imported already. */ public static boolean hasImport( String src, String pkg, String name ) { String[] ss= src.split("\n"); Pattern p= Pattern.compile("from (.+) import (.*)"); boolean haveIt=false; for ( int i=0; i raise exception * Character.isDigit -> string.isnumeric * "".startsWith -> "".startswith * "".trim() -> "".strip() * || -> or * && -> and * ! -> not * int[] d -> d * System.arraycopy -> for i in range(0,6): a[i]=a[i+6] * @param javaCode * @return conversion to Jython-like code. */ public static String convertReverse(String javaCode) { String[] ss= javaCode.split("\n"); StringBuilder b= new StringBuilder(); Pattern assignPattern= Pattern.compile("([a-zA-Z.]*[A-Z]\\S+)(\\s+)(\\S+)(\\s*=.*)"); Pattern importPattern1= Pattern.compile("import ([a-z\\.]*)\\.([A-Za-z\\*]*)"); Pattern newPattern= Pattern.compile("(.*)([=\\s]*)?new\\s*([a-zA-Z\\.]+)(.*)"); int indentLevel= 0; String indent=""; boolean withinComment= false; ArrayList importedPaths= new ArrayList<>(); char[] chrs= new char[] { '(', ')', '{', '}' }; int lineNumber= 0; for ( String s: ss ) { logger.log(Level.FINER, "line {0}: {1}", new Object[]{lineNumber, s}); lineNumber++; String strim= s.trim(); int javaIndent= strim.length()>1 ? s.indexOf(strim.substring(0,1)) : 0; s= strim; indentLevel= javaIndent; if ( indentLevel!=indent.length()) { indent= " ".substring(0,indentLevel); } if ( s.endsWith(";") ) s= s.substring(0,s.length()-1); s= s.replaceAll("//","#"); if ( s.startsWith("/*") ) withinComment= true; Matcher m= newPattern.matcher(s); if ( m.matches() ) { String clas= "import " + m.group(3); if ( !importedPaths.contains(clas) ) { importedPaths.add(clas); } s= m.group(1) + m.group(2) + m.group(3) + m.group(4); } if ( s.contains("Short.") ) { // support Matisse String clas= "from java.lang import Short"; if ( !importedPaths.contains(clas)) { importedPaths.add(clas); } } s= s.replaceAll("null","None"); s= s.replaceAll(" new "," " ); s= s.replaceAll("throw", "raise"); s= s.replaceAll("false","False"); s= s.replaceAll("true","True"); s= s.replaceAll("startsWith","startswith"); s= s.replaceAll("endsWith","endswith"); s= s.replaceAll("else if","elif"); s= s.replaceAll("\\|\\|","or"); s= s.replaceAll("\\&\\&","and"); s= s.replaceAll("String.format\\((.*?),(.*)\\)", "$1 % \\($2\\)"); s= s.replaceAll("public static final ([a-zA-Z0-9_]+)","# returns $1\n"+indent+"def"); s= s.replaceAll("private static final ([a-zA-Z0-9_]+)","# returns $1\n"+indent+"def"); s= s.replaceAll("public static ([a-zA-Z0-9_]+)","# returns $1\n"+indent+"def"); s= s.replaceAll("private static ([a-zA-Z0-9_]+)","# returns $1\n"+indent+"def"); s= s.replaceAll("for\\s+\\(\\s*int\\s+([a-z]+)\\s*=\\s*(\\d+)\\s*\\; \\s*\\1\\s*\\<\\s*(\\d+)\\;\\s*\\1\\+\\+\\s*\\)", "for $1 in xrange($2,$3)"); s= s.replaceAll("\\.substring\\(([a-z\\+\\-\\.0-9]+\\s*)(,\\s*([a-z\\+\\-\\.0-9]+)\\s*)?\\)","[$1:$3]" ); s= s.replaceAll("\\.substring\\(([a-z\\+\\-\\.0-9\\(\\)]+\\s*)(,\\s*([a-z\\+\\-\\.0-9]+)\\s*)?\\)","[$1:$3]" ); s= s.replaceAll(".charAt\\(([a-z\\+\\-\\.0-9\\(\\)]+\\s*)\\)","[$1]" ); s= s.replaceAll("([a-zA-Z0-9_]+).length\\(\\)","len($1)" ); m= assignPattern.matcher(s); if ( m.matches() ) { s= m.group(3)+m.group(4); } else { m= importPattern1.matcher(s); if ( m.matches() ) { s= "from "+m.group(1)+" import "+m.group(2); } } if ( s.contains("reformatIsoTime")) { System.err.println("Stop here jeremy"); } if ( s.contains("{") ) { s= s.replace("{",":"); } if ( s.contains("}") ) { s= s.replace("}",""); } s= s.trim(); b.append(indent); if ( withinComment ) { b.append("# "); if ( s.endsWith("*/") ) withinComment= false; if ( s.startsWith("/*") ) s= s.substring(2).trim(); if ( s.startsWith("*/") ) s= s.substring(2).trim(); if ( s.startsWith("*") ) s= s.substring(1).trim(); } if ( s.startsWith("public static") && s.endsWith("{")) { s= s.substring(13).trim(); int i= s.indexOf(" "); if ( i>0 ) { s= s.substring(i).trim(); } s= "def " + s; } b.append(s).append("\n"); logger.log(Level.FINER, "out {0}: {1}", new Object[]{lineNumber, s}); } StringBuilder sb= new StringBuilder(); for ( String s : importedPaths ) { sb.append(s).append("\n"); } if ( !importedPaths.isEmpty() ) sb.append("\n"); sb.append(b); return sb.toString(); } /** * return the Java type to use for the list. * @param list * @return */ public static String getJavaListType( org.python.parser.ast.List list ) { if ( list.elts.length==0 ) { return "new Object[]"; } else { Object o= list.elts[0]; for ( int i=1; i names= new HashMap<>(); } private static class MyVisitorBase extends VisitorBase { boolean looksOkay = true; boolean visitNameFail = false; StringBuilder builder; int lineNumber = 1; boolean includeLineNumbers = false; // when a Return is encountered, make a note of the return type. String lastReturnType= ""; Stack contexts= new Stack<>(); MyVisitorBase(StringBuilder builder) { this.builder= builder; contexts.push( new Context() ); } @Override public Object visitName(Name node) throws Exception { return super.visitName(node); //To change body of generated methods, choose Tools | Templates. } @Override public Object visitCall(Call node) throws Exception { return super.visitCall(node); //To change body of generated methods, choose Tools | Templates. } @Override protected Object unhandled_node(SimpleNode sn) throws Exception { return sn; } @Override public void traverse(SimpleNode sn) throws Exception { StringBuilder builder= this.builder; traverse( builder,"", sn, false); } private static final Map ops= new HashMap<>(); static { ops.put( 1, "+" ); ops.put( 2, "-" ); ops.put( 3, "*" ); ops.put( 4, "/" ); ops.put( 5, "%" ); ops.put( 9, "|" ); ops.put( 10, "^" ); ops.put( 11, "&" ); ops.put( 12, "/floordiv/" ); }; private static final String spaces4 = " "; public void traverse( StringBuilder builder, String indent, SimpleNode sn, boolean inline) throws Exception { if (includeLineNumbers && (builder.length() == 0 || builder.charAt(builder.length() - 1) == '\n')) { builder.append(String.format("%04d: ", lineNumber)); } // while ( !(sn instanceof TryExcept) && sn.beginLine > lineNumber) { // builder.append("\n"); // lineNumber++; // if (includeLineNumbers) { // builder.append(String.format("%04d: ", lineNumber)); // } // } if ( !inline ) { boolean endsWithIndent= builder.indexOf( indent, builder.length()-indent.length() ) >-1; if (!endsWithIndent) { builder.append(indent); } } //if ( lineNumber==4 ) { // System.err.println("here line number breakpoint at line "+lineNumber ); //} if (sn instanceof FunctionDef) { handleFunctionDef( builder,(FunctionDef)sn, indent, inline ); } else if (sn instanceof ClassDef ) { handleClassDef(builder, (ClassDef)sn, indent, inline ); } else if (sn instanceof Global) { Global g= (Global)sn; builder.append("// global "); for ( int i=0; i0 ) builder.append(","); builder.append(g.names[i]); } } else if (sn instanceof Break ) { builder.append("break"); } else if (sn instanceof Expr) { Expr ex = (Expr) sn; traverse(builder,"", ex.value, true); } else if (sn instanceof Print) { handlePrint( builder, (Print)sn, indent, inline ); } else if (sn instanceof Return) { Return rt = ((Return) sn); builder.append("return"); if ( rt.value!=null ) { builder.append(" "); traverse(builder,"", rt.value, true); lastReturnType= guessType(rt.value); } } else if (sn instanceof ImportFrom) { ImportFrom ff = ((ImportFrom) sn); for (int i = 0; i < ff.names.length; i++) { builder.append("import ").append(ff.module).append('.').append(ff.names[i].name); if ( i"); break; case Compare.GtE: builder.append(">="); break; case Compare.Lt: builder.append("<"); break; case Compare.LtE: builder.append("<="); break; case Compare.Eq: builder.append("=="); break; case Compare.NotEq: builder.append("!="); break; case Compare.In: if ( cp.comparators.length==1 && guessType( cp.comparators[0] )==TYPE_MAP ) { traverse(builder,"", cp.comparators[0], inline); builder.append(".containsKey("); traverse(builder,"", cp.left, inline); builder.append(")"); } else { traverse(builder,"", cp.left, inline); builder.append(""); for (exprType t : cp.comparators) { traverse(builder,"", t, inline); } } break; case Compare.Is: builder.append(" instanceof "); break; default: builder.append("?<>?"); break; } } if ( cp.ops[0]!=Compare.In ) { for (exprType t : cp.comparators) { traverse(builder,"", t, inline); } } } else if (sn instanceof Continue) { builder.append("continue"); } else if (sn instanceof Raise) { Raise r= (Raise)sn; builder.append("throw "); traverse(builder,"", r.type, true ); } else if (sn instanceof ExtSlice ) { ExtSlice r= (ExtSlice)sn; for ( int i=0; i0 ) builder.append(","); sliceType st= r.dims[i]; traverse(builder,"", st, true ); } } else if (sn instanceof Slice) { Slice s= (Slice)sn; builder.append( "[" + String.valueOf(s.lower)+":"+ String.valueOf(s.upper)+":"+ String.valueOf(s.step) + "]" ); } else if (sn instanceof Subscript ) { handleSubscript( builder,(Subscript)sn, indent, inline ); } else if (sn instanceof Attribute) { Attribute at = ((Attribute) sn); String type= guessType(at.value); if ( type.equals("String") ) { if ( at.attr.equals("strip") ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("trim"); return; } else if ( at.attr.equals("split") ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("trim().split(\"\\\\s+\")"); return; } else if ( at.attr.equals("splitlines") ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("split(\"\\n\")"); return; } else if ( at.attr.equals("find") ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("indexOf"); return; } else if ( at.attr.equals("startswith") ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("startsWith"); return; } else if ( at.attr.equals("endswith") ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("endsWith"); return; } } else { if ( at.attr.equals("strip") && ( at.value instanceof Name ) ) { traverse(builder,"", at.value, true); builder.append("."); builder.append("trim"); assertType(((Name)at.value).id, TYPE_STRING ); return; } } traverse(builder,"", at.value, true); builder.append("."); builder.append(at.attr); } else if ( sn instanceof org.python.parser.ast.List ) { org.python.parser.ast.List ll = ((org.python.parser.ast.List) sn); String open= getJavaListType( ll ); builder.append(open); builder.append(" { "); for ( int i=0; i0 ) builder.append(","); traverse(builder,"", ll.elts[i], true); } builder.append(" } "); } else if ( sn instanceof org.python.parser.ast.Subscript ) { org.python.parser.ast.Subscript ss= (org.python.parser.ast.Subscript)sn; traverse( builder,"", ss.value, true ); builder.append("["); traverse( builder,"", ss.slice, true ); builder.append("]"); } else if ( sn instanceof Tuple ) { org.python.parser.ast.Tuple ss= (org.python.parser.ast.Tuple)sn; for ( int i=0; i0 ) builder.append(','); traverse( builder,"", ss.elts[i], true ); } } else if ( sn instanceof AugAssign ) { AugAssign a1= (AugAssign)sn; switch (a1.op) { case AugAssign.Add: traverse(builder,"", a1.target, true); builder.append("+="); traverse(builder,"", a1.value, true); break; case AugAssign.Sub: traverse(builder,"", a1.target, true); builder.append("+="); traverse(builder,"", a1.value, true); break; default: builder.append(sn.toString()).append("\n"); break; } } else if( sn instanceof TryExcept ) { TryExcept te= (TryExcept)sn; System.err.println(""+indent.length()+" length"); builder.append(indent).append("try {\n"); handleBody( builder, te.body, indent+spaces4 ); builder.append(indent).append("} catch ( Exception e ) {").append("\n"); for ( int i=0; i1 ) { builder.append( "not sure line830"); } } else { builder.append( "not sure line833"); } } if ( te.orelse==null ) { } else { builder.append( "not sure line839"); handleBody(builder,te.orelse, indent+spaces4 ); builder.append( "not sure line832"); } builder.append(indent).append("}"); } else if ( sn instanceof Import ) { Import imp= (Import)sn; builder.append( indent ).append( "import " ); for ( aliasType a: imp.names ) { traverse( builder,"", a, true ); builder.append(","); } } else if ( sn instanceof ImportFrom ) { ImportFrom imp= (ImportFrom)sn; builder.append( indent ).append( "import " ) .append( imp.module ); } else if ( sn instanceof aliasType ) { aliasType at= (aliasType)sn; builder.append( indent ).append( at.name ); } else if ( sn instanceof Pass ) { builder.append( indent ).append( "//pass" ); } else if ( sn instanceof Dict ) { builder.append( indent ).append( "new HashMap<>()" ); } else if ( sn instanceof ListComp ) { handleListComp(builder, (ListComp)sn, indent, inline); } else { builder.append(sn.toString()).append("\n"); lineNumber++; } if ( !inline ) { String ss= builder.toString().trim(); if ( ss.charAt(ss.length()-1)=='}' ) { builder.append("\n"); } else { builder.append(";\n"); } lineNumber++; } } public boolean looksOkay() { return looksOkay; } /** * this contains a node whose name we can't resolve. * * @return */ public boolean visitNameFail() { return visitNameFail; } /** * return the type for the name, if the name is known, or null. This * climbs up the stack of contexts, looking for the name * @param name * @return */ private String getTypeForName( String name ) { for ( int i=contexts.size()-1; i>=0; i-- ) { Context c= contexts.get(i); String ss= c.names.get(name); if ( ss!=null ) { return ss; } } return null; } /** * return "String" or "Object * @param ex * @return */ private String guessType( exprType ex ) { if ( ex instanceof Str ) { return TYPE_STRING; } else if ( ex instanceof Num ) { Num n1= ((Num)ex); if ( n1.n instanceof PyInteger ) { return TYPE_INT; } else { return TYPE_FLOAT; } } else if ( ex instanceof Name ) { String s= getTypeForName(((Name)ex).id); if ( s==null ) { //TODO: static return TYPE_OBJECT; } else { return s; } } else if ( ex instanceof Call ) { Call call= (Call)ex; if ( call.func instanceof Attribute ) { Attribute attr= (Attribute)call.func; String type= guessType( attr.value ); if ( type==TYPE_STRING ) { if ( attr.attr.equals("find") ) { return TYPE_INT; } else if ( attr.attr.equals("substring") ) { return TYPE_STRING; } else if ( attr.attr.equals("strip") ) { return TYPE_STRING; } else if ( attr.attr.equals("splitlines") ) { return TYPE_STRING_ARRAY; } } } else if ( call.func instanceof Name ) { Name n= (Name)call.func; if ( n.id.equals("len") ) { return TYPE_INT; } } return TYPE_OBJECT; } else if ( ex instanceof BinOp ) { BinOp bo= (BinOp)ex; String t1= guessType( bo.left ); String t2= guessType( bo.right ); if ( t1==TYPE_INT && t2==TYPE_INT ) { return TYPE_INT; } else if ( t1==TYPE_STRING && t2==TYPE_STRING ) { return TYPE_STRING; } else { return TYPE_OBJECT; } } else if ( ex instanceof Subscript ) { return guessType( ((Subscript)ex).value ); } else { return TYPE_OBJECT; } } /** * this returns the type of objects the iterator iterates over. * @param iter * @return */ private String getJavaIterExprType(exprType iter) { if ( iter instanceof Call ) { Call cc= (Call)iter; if ( cc.func instanceof Name ) { Name n= (Name)cc.func; if ( n.id.equals("range") ) { return "int"; } else if ( n.id.equals("xrange") ) { return "int"; } else if ( n.id.equals("getDataSet") ) { return "QDataSet"; } else if ( n.id.equals("getParam") ) { if ( cc.args.length>1 ) { exprType arg1= cc.args[1]; return getJavaExprType(arg1); } } } else if ( cc.func instanceof Attribute ) { Attribute att= (Attribute)cc.func; if ( att.value instanceof Name ) { Name n= (Name)att.value; String ftype= getJavaExprType(n); // ideally this would be file if ( att.attr.equals("readlines") ) { return TYPE_STRING; } else if ( att.attr.equals("splitlines") ) { return TYPE_STRING; } } } } return "Object"; } /** * there's an issue here where for iter==Call, this is returning the * object which the iterator returns. * @param iter * @return */ private String getJavaExprType(exprType iter) { if ( iter instanceof Call ) { Call cc= (Call)iter; if ( cc.func instanceof Name ) { Name n= (Name)cc.func; if ( n.id.equals("int") ) { return TYPE_INT; } else if ( n.id.equals("range") ) { return "Stream"; } else if ( n.id.equals("xrange") ) { return "Stream"; } else if ( n.id.equals("getDataSet") ) { return "QDataSet"; } else if ( n.id.equals("downloadResourceAsTempFile") ) { return "File"; } else if ( n.id.equals("getParam") ) { if ( cc.args.length>1 ) { exprType arg1= cc.args[1]; return getJavaExprType(arg1); } } else if ( Character.isUpperCase(n.id.charAt(0)) ) { return n.id; // assume it's a constructor } else if ( n.id.equals("open") ) { return "Stream"; } } else if ( cc.func instanceof Attribute ) { Attribute attr= (Attribute)cc.func; String staticClass= ""; if ( attr.value instanceof Name ) { if ( Character.isUpperCase(((Name)attr.value).id.charAt(0)) ) { staticClass= ((Name)attr.value).id; } } if (attr instanceof Attribute ) { Attribute attr2= (Attribute)attr; if ( attr2.attr.equals("strip") ) { return TYPE_STRING; } else if ( attr2.attr.equals("split") ) { return TYPE_STRING_ARRAY; } } if ( staticClass.equals("FileUtil") && attr.attr.equals("readFileToString") ) { return TYPE_STRING; } } } else if ( iter instanceof Str ) { return TYPE_STRING; } else if ( iter instanceof Name ) { Name n= (Name)iter; if ( n.id.equals("False") || n.id.equals("True")) { return "boolean"; } else { return TYPE_OBJECT; } } else if ( iter instanceof Num ) { Num n= (Num)iter; if ( n.n instanceof PyFloat ) { return "float"; } else if ( n.n instanceof PyInteger ) { return "int"; } else { return "Number"; } } else if ( iter instanceof Str ) { return "String"; } else if ( iter instanceof org.python.parser.ast.List ) { org.python.parser.ast.List l = (org.python.parser.ast.List)iter; String t0=null; for ( exprType e1 : l.elts ) { String t1= getJavaExprType(e1); if ( t0==null ) { t0= t1; } else if ( !t0.equals(t1) ) { return "Object[]"; } } if ( t0==null ) { return "Object[]"; } else { return t0+"[]"; } } else if ( iter instanceof Subscript ) { Subscript s= (Subscript)iter; String type= guessType(s.value); if ( type.equals( TYPE_OBJECT ) ) { type= getJavaExprType( s.value ); } if ( type.endsWith("[]") ) { return type.substring(0,type.length()-2).intern(); } else { return TYPE_OBJECT; } } else if ( iter instanceof Dict ) { return TYPE_MAP; } return "Object"; } /** * assert that the symbol has the name * @param name * @param type type, including String or Stream<String> */ private void assertType( String name, String type ) { contexts.peek().names.put( name, type ); } private String guessReturnType( stmtType[] statements ) { this.lastReturnType= "Object"; StringBuilder dummy= new StringBuilder(); try { handleBody(dummy,statements,""); } catch (Exception ex) { Logger.getLogger(JythonToJavaConverter.class.getName()).log(Level.SEVERE, null, ex); } return this.lastReturnType; } private void handleFunctionDef( StringBuilder builder, FunctionDef fd, String indent, boolean inline ) throws Exception { String returnType= guessReturnType(fd.body ); // check for single-line documentation string if ( fd.body.length>0 && fd.body[0] instanceof Expr ) { Expr expr= (Expr)fd.body[0]; if ( expr.value instanceof Str ) { builder .append(indent).append("/**\n") .append(indent).append(" * ").append(((Str)expr.value).s).append("\n") .append(indent).append(" */\n"); fd.body= Arrays.copyOfRange( fd.body, 1, fd.body.length ); } } builder.append("private ").append(returnType).append(" ").append(fd.name).append("("); for (int i = 0; i < fd.args.args.length; i++) { if (i > 0) { builder.append(","); } traverse( builder,"", fd.args.args[i], true ); } builder.append(") {\n"); lineNumber++; handleBody(builder, fd.body, indent+spaces4 ); builder.append(indent).append("}"); } private void handlePrint( StringBuilder builder, Print pr, String indent, boolean inline) throws Exception { builder.append("System.out.println("); for (int i = 0; i < pr.values.length; i++) { if (i > 0) { builder.append(","); } traverse(builder,"", pr.values[i], true); } builder.append(")"); } private void handleClassDef( StringBuilder builder, ClassDef classDef, String indent, boolean inline) throws Exception { if ( classDef.bases.length>0 ) { builder.append("private class ").append(classDef.name).append(" extends "); traverse( builder, indent, classDef.bases[0], true ); builder.append(" {"); } else { builder.append("private class ").append(classDef.name).append(" {"); } handleBody( builder,classDef.body, indent+spaces4 ); builder.append("}"); } private void handleAssign(StringBuilder builder, Assign as, String indent, boolean inline) throws Exception { logger.log(Level.FINE, "handleAssign at {0}", as.beginLine); if ( as.targets[0] instanceof Subscript && as.targets.length==1 ) { // is this an assignment to a dictionary Subscript subscript = (Subscript)as.targets[0]; if ( subscript.value instanceof Name ) { Name name= (Name)subscript.value; if ( guessType( subscript.value ).equals("Map") ) { builder.append(indent).append(name.id).append(".put("); traverse(builder,"", subscript.slice, true); builder.append(indent).append(","); traverse(builder,"", as.value, true); builder.append(indent).append(")"); return; } } } if ( as.targets.length==1 && ( as.targets[0] instanceof Name ) ) { String typeOf1= guessType( ((Name)as.targets[0]) ); if ( typeOf1==null || typeOf1==TYPE_OBJECT ) { String typeOf= getJavaExprType( as.value ); if ( typeOf==TYPE_OBJECT ) { typeOf=guessType(as.value); } builder.append(typeOf).append(" "); assertType( ((Name)as.targets[0]).id, typeOf ); } } for (int i = 0; i < as.targets.length; i++) { if (i > 0) { builder.append(","); } traverse(builder,"", as.targets[i], true); } builder.append(" = "); traverse(builder,"", as.value, true); } private void handleListComp( StringBuilder builder, ListComp lc, String indent, boolean inline) throws Exception { if ( lc.generators.length==1 ) { if ( lc.generators[0] instanceof listcompType ) { listcompType lct= (listcompType)lc.generators[0]; if ( lct.ifs.length==0 ) { traverse(builder,"", lct.iter, true ); builder.append(".stream().map( "); traverse(builder,"", lct.target, true ); builder.append(" -> "); traverse(builder,"", lc.elt, true ); builder.append(").collect(Collectors.toList())"); return; } } } builder.append(lc.toString()); } private void handleName(StringBuilder builder, Name nn, String indent, boolean inline) { String name= nn.id; if ( name.equals("False") ) { builder.append("false"); } else if ( name.equals("True") ) { builder.append("true"); } else if ( name.equals("None") ) { builder.append("null"); } else { builder.append(nn.id); } } private void handleCall(StringBuilder builder, Call cc, String indent, boolean inline) throws Exception { if (cc.func instanceof Name) { String name = ((Name) cc.func).id; if (Character.isUpperCase(name.charAt(0))) { builder.append("new").append(" "); } else if ( name.equals("int") ) { builder.append("(int)("); traverse(builder,"",cc.args[0],true); builder.append(")"); return; } } else if ( cc.func instanceof Attribute ) { // static method exprType clas= ((Attribute) cc.func).value; String method = ((Attribute) cc.func).attr; if ( clas instanceof Name ) { String n= ((Name)clas).id; if ( n.equals("struct") ) { if ( method.equals("pack") ) { System.err.println( "struct.pack could be implemented with ByteBuffer maybe" ); } } } } traverse(builder,"", cc.func, true); builder.append("("); for (int i = 0; i < cc.args.length; i++) { if (i > 0) { builder.append(","); } traverse(builder,"", cc.args[i], true); } builder.append(")"); for ( int i=0; i