package org.autoplot.jythonsupport; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Stack; import java.util.StringTokenizer; import java.util.regex.Pattern; import javax.swing.JDialog; import javax.swing.JEditorPane; import jsyntaxpane.DefaultSyntaxKit; /** * Tool for converting Mathematica expressions into Jython code. * @author jbf */ public class MathematicaJythonConverter extends javax.swing.JPanel { /** * Creates new form JavaJythonConverter * @param editor editor from which preferences come */ public MathematicaJythonConverter( JEditorPane editor ) { initComponents(); DefaultSyntaxKit.initKit(); mathematicaEditorPane.setContentType("text/java"); DefaultSyntaxKit.initKit(); jythonEditorPane.setContentType("text/python"); if ( editor!=null ) { mathematicaEditorPane.setBackground( editor.getBackground() ); mathematicaEditorPane.setForeground( editor.getForeground() ); mathematicaEditorPane.setFont(editor.getFont()); jythonEditorPane.setBackground( editor.getBackground() ); jythonEditorPane.setForeground( editor.getForeground() ); jythonEditorPane.setFont(editor.getFont()); } } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { jPanel1 = new javax.swing.JPanel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); jPanel2 = new javax.swing.JPanel(); jSplitPane1 = new javax.swing.JSplitPane(); jPanel3 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); mathematicaEditorPane = new javax.swing.JEditorPane(); jPanel4 = new javax.swing.JPanel(); jScrollPane2 = new javax.swing.JScrollPane(); jythonEditorPane = new javax.swing.JEditorPane(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jButton1.setText("Convert Mathematica to Jython -->"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton1ActionPerformed(evt); } }); jButton2.setText("Copy Jython to Clipboard"); jButton2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton2ActionPerformed(evt); } }); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGap(318, 318, 318) .addComponent(jButton1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 344, Short.MAX_VALUE) .addComponent(jButton2)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jButton1) .addComponent(jButton2)) ); jSplitPane1.setDividerLocation(400); jSplitPane1.setResizeWeight(0.5); jLabel1.setText("Mathematica Code"); jScrollPane1.setViewportView(mathematicaEditorPane); javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 442, Short.MAX_VALUE) .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup() .addGap(31, 31, 31) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 641, Short.MAX_VALUE)) .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel3Layout.createSequentialGroup() .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 648, Short.MAX_VALUE))) ); jSplitPane1.setLeftComponent(jPanel3); jScrollPane2.setViewportView(jythonEditorPane); jLabel2.setText("Jython Code"); javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4); jPanel4.setLayout(jPanel4Layout); jPanel4Layout.setHorizontalGroup( jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel4Layout.createSequentialGroup() .addComponent(jLabel2) .addGap(0, 609, Short.MAX_VALUE)) .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 694, Short.MAX_VALUE)) ); jPanel4Layout.setVerticalGroup( jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel4Layout.createSequentialGroup() .addComponent(jLabel2) .addGap(0, 657, Short.MAX_VALUE)) .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel4Layout.createSequentialGroup() .addGap(29, 29, 29) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 643, Short.MAX_VALUE))) ); jSplitPane1.setRightComponent(jPanel4); javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING) ); jLabel3.setFont(new java.awt.Font("Dialog", 2, 12)); // NOI18N jLabel3.setText("This is an experimental tool for converting Mathematica code into Jython code. Please verify results before using this in production code."); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, Short.MAX_VALUE)) .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(2, 2, 2) .addComponent(jLabel3) .addGap(1, 1, 1) .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap()) ); }// //GEN-END:initComponents private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed String m= mathematicaEditorPane.getText(); String jython= convertMathematicaToJython(m); jythonEditorPane.setText(jython); }//GEN-LAST:event_jButton1ActionPerformed /** * Sqrt[(-(1836/(fce-fr))+1/(fci+fr))/fr] * @param sb the output * @param stack the stack of unhandled tokens * @param t the next token * @return true if the token has been handled. */ private static boolean checkPop(StringBuilder sb, Stack stack, String t) { if ( !stack.empty() ) { String s= stack.peek(); if ( t.equals("]") ) { List ss= new LinkedList<>(); ss.add(t); while ( !stack.isEmpty() && !s.equals("[") ) { s= stack.pop(); ss.add(0,s); } if ( !s.equals("[") ) { throw new IllegalArgumentException("opening bracket ([) not found"); } if ( ss.size()==3 && ss.get(1).equals("Sqrt") ) { sb.append("sqrt"); } else { for ( String ss1: ss ) { char c= ss1.charAt(0); switch (c) { case '[': sb.append('('); break; case ']': sb.append(')'); break; default: sb.append(ss1); break; } } } return true; } } return false; } /** * quick-n-dirty converter for converting Mathematica code to Jython code. * @param m * @return */ public static String convertMathematicaToJython(String m) { int assign= m.indexOf("->"); if ( assign>-1 ) { m= m.substring(0,assign)+"=" + m.substring(assign+2); } m= m.replaceAll("\\\\\\[", "["); StringTokenizer st= new StringTokenizer( m, "{-> (/[]+-^=)}", true ); Stack stack= new Stack(); StringBuilder sb= new StringBuilder(); boolean lastNameOrConstant= false; String lastToken=""; Pattern intPattern= Pattern.compile("\\d+"); while ( st.hasMoreTokens() ) { String t= st.nextToken(); if ( checkPop( sb, stack, t ) ) { continue; } if ( !stack.isEmpty() ) { stack.add(t); continue; } if ( t.equals(" ") ) { if ( !lastNameOrConstant ) { sb.append(t); } } else if ( t.equals("\n") ) { sb.append(t); } else if ( t.equals("{") ) { } else if ( t.equals("}") ) { } else if ( t.equals("=") ) { sb.append("="); lastNameOrConstant= false; } else if ( t.equals("[") ) { stack.push(t); } else if ( t.equals("]") ) { String lastt= stack.pop(); if ( !stack.isEmpty() && stack.peek().equals("[") ) { stack.pop(); if ( lastNameOrConstant ) { sb.append(" * "); } if ( lastt.equals("Sqrt") ) { sb.append("sqrt"); lastNameOrConstant= false; } else { sb.append('(').append(lastt).append(')'); lastNameOrConstant= true; } } else { sb.append(")"); } } else if ( t.equals("(") ) { if ( lastToken.equals(")") ) { sb.append(" * "); } else if ( lastToken.equals("[") ) { sb.append("("); } else if ( lastNameOrConstant ) { sb.append("* "); } sb.append(t); lastNameOrConstant= false; } else if ( t.equals(")") ) { sb.append(t); lastNameOrConstant= true; } else if ( t.equals("^") ) { sb.append("**"); lastNameOrConstant= false; } else if ( t.equals("+") ) { sb.append(" ").append(t).append(" "); lastNameOrConstant= false; } else if ( t.equals("-") ) { if ( lastNameOrConstant ) { sb.append(" ").append(t); } else { sb.append(t); } lastNameOrConstant= false; } else if ( t.equals("/") ) { sb.append(t); lastNameOrConstant= false; } else if ( intPattern.matcher(t).matches() ) { if ( !stack.isEmpty() ) { stack.push(t); } else { if ( lastNameOrConstant ) { sb.append("*"); } if ( lastToken.equals("/") ) { sb.append(t).append("."); } else { sb.append(t); } lastNameOrConstant= true; } } else { if ( !stack.isEmpty() ) { stack.push(t); } else { boolean isFunctionName= false; if ( t.equals("Sqrt") ) { t= "sqrt"; isFunctionName= true; } if ( lastNameOrConstant ) { sb.append("*"); } sb.append(t); lastNameOrConstant= !isFunctionName; } } //System.out.print( t ); lastToken= t; } String jython= sb.toString(); return jython; } private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); StringSelection ss= new StringSelection( jythonEditorPane.getText() ); clipboard.setContents( ss, new ClipboardOwner() { @Override public void lostOwnership(Clipboard clipboard, Transferable contents) { } }); }//GEN-LAST:event_jButton2ActionPerformed public static void main( String[] args ) throws IOException { MathematicaJythonConverter cc= new MathematicaJythonConverter(null); String src1= "{flh -> (1/(\n" + " 6 Sqrt[102]))(\\[Sqrt](1836 fce^2 + 1836 fci^2 +\n" + " 1837 fpe^2 - \\[Sqrt](3370896 fce^4 - 6741792 fce^2 fci^2 +\n" + " 3370896 fci^4 + 6738120 fce^2 fpe^2 - 6738120 fci^2 fpe^2 +\n" + " 3374569 fpe^4)))}"; String src2= "fl -> 1/306 (102 (fce + fci) - (17^(\n" + " 2/3) (612 fce^2 - 612 fce fci + 612 fci^2 +\n" + " 1837 fpe^2))/(-62424 fce^3 + 93636 fce^2 fci +\n" + " 93636 fce fci^2 - 62424 fci^3 - 280602 fce fpe^2 +\n" + " 561663 fci fpe^2 +\n" + " Sqrt[17] \\[Sqrt](-(612 fce^2 - 612 fce fci + 612 fci^2 +\n" + " 1837 fpe^2)^3 +\n" + " 1377 (408 fce^3 - 612 fce^2 fci - 612 fce fci^2 +\n" + " 408 fci^3 + 1834 fce fpe^2 - 3671 fci fpe^2)^2))^(\n" + " 1/3) - 17^(\n" + " 1/3) (-62424 fce^3 + 93636 fce^2 fci + 93636 fce fci^2 -\n" + " 62424 fci^3 - 280602 fce fpe^2 + 561663 fci fpe^2 +\n" + " Sqrt[17] \\[Sqrt](-(612 fce^2 - 612 fce fci + 612 fci^2 +\n" + " 1837 fpe^2)^3 +\n" + " 1377 (408 fce^3 - 612 fce^2 fci - 612 fce fci^2 +\n" + " 408 fci^3 + 1834 fce fpe^2 - 3671 fci fpe^2)^2))^(\n" + " 1/3))}"; String src3= "{fpe->(6 Sqrt[51])/Sqrt[(-(1836/(fce-fr))+1/(fci+fr))/fr]}"; String src= src2; cc.mathematicaEditorPane.setText(src); JDialog dia= new JDialog(); dia.setContentPane( cc ); dia.pack(); dia.setVisible(true); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JPanel jPanel4; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JEditorPane jythonEditorPane; private javax.swing.JEditorPane mathematicaEditorPane; // End of variables declaration//GEN-END:variables public void setJavaSource(String doThis) { mathematicaEditorPane.setText(doThis); } }