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);
}
}