package bigstep.test;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import bigstep.BigStepProofModel;
import bigstep.BigStepProofModelFactory;
import bigstep.BigStepProofNode;
import common.ProofNode;
/**
* Test class for the big step interpreter.
*
* @author Benedikt Meurer
* @version $Id$
*/
@SuppressWarnings("serial")
public class BigStepTreeView extends JFrame {
/**
* Simple test expression.
*/
//private static final String SIMPLE = "(lambda id.id) 1";
//private static final String SIMPLE = "1 + 2 * (4 / 5)";
//private static final String SIMPLE = "if true then 1 + (0 / 0) else 1 / 0";
//private static final String SIMPLE = "let rec f x = if x = 0 then 1 else x * f (x - 1) in f 3";
//private static final String SIMPLE = "#2_2 (1 + 1, 2 + 2, 3 + 3, (4 + 4))";
//private static final String SIMPLE = "let (x, y, z) = (1, 2, 3) in x + z + y";
//private static final String SIMPLE = "let f = lambda (x, y, z).x + y + z in f (1, 2, 3)";
//private static final String SIMPLE = "1 + 1;2 + 2; 3+3";
//private static final String SIMPLE = "let v = ref (1) in !v";
//private static final String SIMPLE = "let f = ref (lambda x.x) in f := (lambda x.if x = 0 then 1 else x * ! f (x - 1)); ! f 3";
//private static final String SIMPLE = "let y = ref 1 in let x = ref 3 in (while (!x > 0) do (y := !y * !x; x := !x - 1)); !y";
private static final String SIMPLE = "rec f:unit->unit.lambda (x, y) : int->bool.x + y";
//
// Renderer
//
/**
* The tree renderer.
*/
class Renderer extends DefaultTreeCellRenderer {
/**
* {@inheritDoc}
*
* @see javax.swing.tree.DefaultTreeCellRenderer#getTreeCellRendererComponent(javax.swing.JTree, java.lang.Object, boolean, boolean, boolean, int, boolean)
*/
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
BigStepProofNode node = (BigStepProofNode)value;
StringBuilder builder = new StringBuilder();
boolean memoryEnabled = ((BigStepProofModel)tree.getModel()).isMemoryEnabled();
builder.append('[');
for (int n = 0; n < node.getSteps().length; ++n) {
if (n > 0)
builder.append(", ");
builder.append(node.getSteps()[n].getRule().getName());
}
builder.append("] -> ");
if (memoryEnabled) {
builder.append('(');
}
builder.append(node.getExpression());
if (memoryEnabled) {
builder.append(", ");
builder.append(node.getStore());
builder.append(')');
}
builder.append(" \u21d3 ");
if (node.getResult() != null) {
if (memoryEnabled) {
builder.append('(');
}
builder.append(node.getResult().getValue());
if (memoryEnabled) {
builder.append(", ");
builder.append(node.getResult().getStore());
builder.append(')');
}
}
setText(builder.toString());
return this;
}
}
//
// Constructor
//
/**
* Default constructor.
*/
public BigStepTreeView(final BigStepProofModel model) {
// setup the frame
setLayout(new BorderLayout());
setSize(630, 580);
setTitle("BigStepTreeView test");
// setup the tree panel
JPanel treePanel = new JPanel(new BorderLayout());
treePanel.setBorder(BorderFactory.createEtchedBorder());
add(treePanel, BorderLayout.CENTER);
// setup the tree
final JTree tree = new JTree(model);
tree.setCellRenderer(new Renderer());
treePanel.add(tree, BorderLayout.CENTER);
// setup the button panel
JPanel buttons = new JPanel(new FlowLayout());
add(buttons, BorderLayout.SOUTH);
// setup the guess button
JButton guessButton = new JButton("Guess");
guessButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
// guess the last node
model.guess(nextNode(model));
// expand to the all nodes
for (int n = 0; n < tree.getRowCount(); ++n) {
tree.expandRow(n);
}
}
catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(BigStepTreeView.this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
buttons.add(guessButton);
// setup the undo button
final JButton undoButton = new JButton("Undo");
undoButton.setEnabled(false);
undoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
// undo the last change
model.undo();
}
catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(BigStepTreeView.this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
model.addPropertyChangeListener("undoable", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
undoButton.setEnabled(model.isUndoable());
}
});
buttons.add(undoButton);
// setup the redo button
final JButton redoButton = new JButton("Redo");
redoButton.setEnabled(false);
redoButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
// redo the last undone change
model.redo();
// expand to the last node
for (int n = 0; n < tree.getRowCount(); ++n) {
tree.expandRow(n);
}
}
catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(BigStepTreeView.this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
model.addPropertyChangeListener("redoable", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
redoButton.setEnabled(model.isRedoable());
}
});
buttons.add(redoButton);
// setup the translate button
JButton translateButton = new JButton("Translate");
translateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
// translate the last node
TreePath path = tree.getSelectionPath();
if (path != null) {
model.translateToCoreSyntax((ProofNode)path.getLastPathComponent());
}
}
catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(BigStepTreeView.this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
buttons.add(translateButton);
// setup the close button
JButton closeButton = new JButton("Close");
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
buttons.add(closeButton);
}
private static ProofNode nextNode(BigStepProofModel model) {
LinkedList<ProofNode> nodes = new LinkedList<ProofNode>();
nodes.add(model.getRoot());
while (!nodes.isEmpty()) {
ProofNode node = nodes.poll();
if (node.getSteps().length == 0) {
return node;
}
for (int n = 0; n < node.getChildCount(); ++n) {
nodes.add(node.getChildAt(n));
}
}
throw new IllegalStateException("Unable to find next node");
}
//
// Program entry point
//
/**
* Runs the small step interpreter test.
*
* @param args the command line arguments.
*/
public static void main(String[] args) {
try {
// parse the program
BigStepProofModelFactory factory = BigStepProofModelFactory.newInstance();
BigStepProofModel model = factory.newProofModel(SIMPLE);
// evaluate the resulting small step expression
BigStepTreeView tv = new BigStepTreeView(model);
tv.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
tv.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
}