mirror of
https://github.com/DanilaFe/abacus
synced 2024-11-04 18:08:31 -08:00
Merge branch 'master' of https://github.com/DanilaFe/abacus
This commit is contained in:
commit
f35f83a92f
|
@ -8,3 +8,5 @@
|
|||
* Rembulan(5.3) - https://github.com/mjanicek/rembulan
|
||||
* LuaJava - https://github.com/jasonsantos/luajava
|
||||
* jnlua - https://code.google.com/archive/p/jnlua/
|
||||
## Gist
|
||||
* https://gist.github.com/rileyJones/1c18338821b88e92a477bfa270344db3
|
||||
|
|
|
@ -23,7 +23,7 @@ public class Abacus {
|
|||
}
|
||||
manager = new PluginManager();
|
||||
manager.addInstantiated(new StandardPlugin(manager));
|
||||
mainUi = new Window();
|
||||
mainUi = new Window(manager);
|
||||
mainUi.setVisible(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,11 +87,12 @@ public class Lexer<T> {
|
|||
int index = startAt;
|
||||
ArrayList<Match<T>> matches = new ArrayList<>();
|
||||
Match<T> lastMatch = null;
|
||||
while((lastMatch = lexOne(from, index, compare)) != null && index < from.length()){
|
||||
while(index < from.length() && (lastMatch = lexOne(from, index, compare)) != null){
|
||||
if(lastMatch.getTo() == lastMatch.getFrom()) return null;
|
||||
matches.add(lastMatch);
|
||||
index += lastMatch.getTo() - lastMatch.getFrom();
|
||||
}
|
||||
if(lastMatch == null) return null;
|
||||
return matches;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,4 +44,9 @@ public class NumberNode extends TreeNode {
|
|||
public NumberInterface getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T reduce(Reducer<T> reducer) {
|
||||
return reducer.reduceNode(this);
|
||||
}
|
||||
}
|
||||
|
|
26
src/org/nwapw/abacus/tree/NumberReducer.java
Normal file
26
src/org/nwapw/abacus/tree/NumberReducer.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
package org.nwapw.abacus.tree;
|
||||
|
||||
import org.nwapw.abacus.number.NumberInterface;
|
||||
import org.nwapw.abacus.plugin.PluginManager;
|
||||
|
||||
public class NumberReducer implements Reducer<NumberInterface> {
|
||||
|
||||
private PluginManager manager;
|
||||
|
||||
public NumberReducer(PluginManager manager){
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberInterface reduceNode(TreeNode node, Object... children) {
|
||||
if(node instanceof NumberNode) {
|
||||
return ((NumberNode) node).getNumber();
|
||||
} else if(node instanceof OpNode){
|
||||
NumberInterface left = (NumberInterface) children[0];
|
||||
NumberInterface right = (NumberInterface) children[1];
|
||||
return manager.functionFor(((OpNode) node).getOperation()).apply(left, right);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,8 @@ public class OpNode extends TreeNode {
|
|||
*/
|
||||
private TreeNode right;
|
||||
|
||||
private OpNode() {}
|
||||
|
||||
/**
|
||||
* Creates a new operation node with the given operation
|
||||
* and no child nodes.
|
||||
|
@ -79,4 +81,11 @@ public class OpNode extends TreeNode {
|
|||
public void setRight(TreeNode right) {
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T reduce(Reducer<T> reducer) {
|
||||
T leftReduce = left.reduce(reducer);
|
||||
T rightReduce = right.reduce(reducer);
|
||||
return reducer.reduceNode(this, leftReduce, rightReduce);
|
||||
}
|
||||
}
|
||||
|
|
17
src/org/nwapw/abacus/tree/Reducer.java
Normal file
17
src/org/nwapw/abacus/tree/Reducer.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package org.nwapw.abacus.tree;
|
||||
|
||||
/**
|
||||
* Interface used to reduce a tree into a single value.
|
||||
* @param <T> the value to reduce into.
|
||||
*/
|
||||
public interface Reducer<T> {
|
||||
|
||||
/**
|
||||
* Reduces the given tree into a single value of type T.
|
||||
* @param node the node being passed in to be reduced.
|
||||
* @param children the already-reduced children of this node.
|
||||
* @return the resulting value from the reduce.
|
||||
*/
|
||||
public T reduceNode(TreeNode node, Object...children);
|
||||
|
||||
}
|
|
@ -14,7 +14,6 @@ public abstract class TreeNode {
|
|||
* The lexer used to lex tokens.
|
||||
*/
|
||||
private static Lexer<TokenType> lexer = new Lexer<TokenType>(){{
|
||||
register(".", TokenType.ANY);
|
||||
register("\\+|-|\\*|/|^", TokenType.OP);
|
||||
register("[0-9]+(\\.[0-9]+)?", TokenType.NUM);
|
||||
register("[a-zA-Z]+", TokenType.WORD);
|
||||
|
@ -130,11 +129,15 @@ public abstract class TreeNode {
|
|||
* @return the resulting tree.
|
||||
*/
|
||||
public static TreeNode fromString(String string){
|
||||
ArrayList<Match<TokenType>> matches = intoPostfix(string, tokenize(string));
|
||||
ArrayList<Match<TokenType>> matches = tokenize(string);
|
||||
if(matches == null) return null;
|
||||
matches = intoPostfix(string, matches);
|
||||
if(matches == null) return null;
|
||||
|
||||
Collections.reverse(matches);
|
||||
return fromStringRecursive(string, matches);
|
||||
}
|
||||
|
||||
public abstract <T> T reduce(Reducer<T> reducer);
|
||||
|
||||
}
|
||||
|
|
97
src/org/nwapw/abacus/window/HistoryTableModel.java
Normal file
97
src/org/nwapw/abacus/window/HistoryTableModel.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package org.nwapw.abacus.window;
|
||||
|
||||
import org.nwapw.abacus.tree.TreeNode;
|
||||
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class HistoryTableModel extends AbstractTableModel {
|
||||
|
||||
public static final String[] COLUMN_NAMES = {
|
||||
"Input",
|
||||
"Parsed Input",
|
||||
"Output"
|
||||
};
|
||||
|
||||
public static final Class[] CLASS_TYPES = {
|
||||
String.class,
|
||||
TreeNode.class,
|
||||
String.class
|
||||
};
|
||||
|
||||
public static class HistoryEntry {
|
||||
public String input;
|
||||
public TreeNode parsedInput;
|
||||
public String output;
|
||||
|
||||
public HistoryEntry(String input, TreeNode parsedInput, String output){
|
||||
this.input = input;
|
||||
this.parsedInput = parsedInput;
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
Object nthValue(int n){
|
||||
if(n == 0) return input;
|
||||
if(n == 1) return parsedInput;
|
||||
if(n == 2) return output;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<HistoryEntry> entries;
|
||||
|
||||
public HistoryTableModel() {
|
||||
entries = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addEntry(HistoryEntry entry){
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int columnIndex) {
|
||||
return COLUMN_NAMES[columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
return CLASS_TYPES[columnIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
return entries.get(rowIndex).nthValue(columnIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableModelListener(TableModelListener l) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTableModelListener(TableModelListener l) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,13 +1,35 @@
|
|||
package org.nwapw.abacus.window;
|
||||
|
||||
import org.nwapw.abacus.plugin.PluginManager;
|
||||
import org.nwapw.abacus.tree.NumberReducer;
|
||||
import org.nwapw.abacus.tree.TreeNode;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
/**
|
||||
* The main UI window for the calculator.
|
||||
*/
|
||||
public class Window extends JFrame {
|
||||
|
||||
private static final String CALC_STRING = "Calculate";
|
||||
private static final String SELECT_STRING = "Select";
|
||||
private static final String SYNTAX_ERR_STRING = "Syntax Error";
|
||||
private static final String NUMBER_SYSTEM_LABEL = "Number Type:";
|
||||
private static final String FUNCTION_LABEL = "Functions:";
|
||||
|
||||
/**
|
||||
* The plugin manager used to retrieve functions.
|
||||
*/
|
||||
private PluginManager manager;
|
||||
/**
|
||||
* The reducer used to evaluate the tree.
|
||||
*/
|
||||
private NumberReducer reducer;
|
||||
|
||||
/**
|
||||
* A collection of outputs from the calculator.
|
||||
*/
|
||||
|
@ -26,13 +48,17 @@ public class Window extends JFrame {
|
|||
*/
|
||||
private JTextArea lastOutputArea;
|
||||
/**
|
||||
* The text area used for all history output.
|
||||
* The table used for storing history results.
|
||||
*/
|
||||
private JTextArea historyArea;
|
||||
private JTable historyTable;
|
||||
/**
|
||||
* The table model used for managing history.
|
||||
*/
|
||||
private HistoryTableModel historyModel;
|
||||
/**
|
||||
* The scroll pane for the history area.
|
||||
*/
|
||||
private JScrollPane historyAreaScroll;
|
||||
private JScrollPane historyScroll;
|
||||
|
||||
/**
|
||||
* The panel where the input occurs.
|
||||
|
@ -74,9 +100,21 @@ public class Window extends JFrame {
|
|||
*/
|
||||
private JButton functionSelectButton;
|
||||
|
||||
public Window() {
|
||||
super();
|
||||
/**
|
||||
* Creates a new window with the given manager.
|
||||
* @param manager the manager to use.
|
||||
*/
|
||||
public Window(PluginManager manager){
|
||||
this();
|
||||
this.manager = manager;
|
||||
reducer = new NumberReducer(manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new window.
|
||||
*/
|
||||
private Window() {
|
||||
super();
|
||||
|
||||
history = "";
|
||||
lastOutput = "";
|
||||
|
@ -84,37 +122,37 @@ public class Window extends JFrame {
|
|||
setSize(640, 480);
|
||||
|
||||
inputField = new JTextField();
|
||||
inputEnterButton = new JButton("Calculate");
|
||||
inputEnterButton = new JButton(CALC_STRING);
|
||||
|
||||
inputPanel = new JPanel();
|
||||
inputPanel.setLayout(new BorderLayout());
|
||||
inputPanel.add(inputField, BorderLayout.CENTER);
|
||||
inputPanel.add(inputEnterButton, BorderLayout.EAST);
|
||||
|
||||
historyArea = new JTextArea(history);
|
||||
historyAreaScroll = new JScrollPane(historyArea);
|
||||
historyModel = new HistoryTableModel();
|
||||
historyTable = new JTable(historyModel);
|
||||
historyScroll = new JScrollPane(historyTable);
|
||||
lastOutputArea = new JTextArea(lastOutput);
|
||||
lastOutputArea.setEditable(false);
|
||||
lastOutputArea.setText(":)");
|
||||
|
||||
outputPanel = new JPanel();
|
||||
outputPanel.setLayout(new BorderLayout());
|
||||
outputPanel.add(historyAreaScroll, BorderLayout.CENTER);
|
||||
outputPanel.add(historyScroll, BorderLayout.CENTER);
|
||||
outputPanel.add(lastOutputArea, BorderLayout.SOUTH);
|
||||
|
||||
numberSystemList = new JComboBox<>();
|
||||
|
||||
numberSystemPanel = new JPanel();
|
||||
numberSystemPanel.setLayout(new BorderLayout());
|
||||
numberSystemPanel.add(new JLabel("Number Type:"), BorderLayout.NORTH);
|
||||
numberSystemPanel.add(new JLabel(NUMBER_SYSTEM_LABEL), BorderLayout.NORTH);
|
||||
numberSystemPanel.add(numberSystemList, BorderLayout.CENTER);
|
||||
|
||||
functionList = new JComboBox<>();
|
||||
functionSelectButton = new JButton("Select");
|
||||
functionSelectButton = new JButton(SELECT_STRING);
|
||||
|
||||
functionSelectPanel = new JPanel();
|
||||
functionSelectPanel.setLayout(new BorderLayout());
|
||||
functionSelectPanel.add(new JLabel("Functions:"), BorderLayout.NORTH);
|
||||
functionSelectPanel.add(new JLabel(FUNCTION_LABEL), BorderLayout.NORTH);
|
||||
functionSelectPanel.add(functionList, BorderLayout.CENTER);
|
||||
functionSelectPanel.add(functionSelectButton, BorderLayout.SOUTH);
|
||||
|
||||
|
@ -126,5 +164,33 @@ public class Window extends JFrame {
|
|||
add(outputPanel, BorderLayout.CENTER);
|
||||
add(sidePanel, BorderLayout.EAST);
|
||||
add(inputPanel, BorderLayout.SOUTH);
|
||||
|
||||
inputEnterButton.addActionListener((event) -> {
|
||||
TreeNode parsedExpression = TreeNode.fromString(inputField.getText());
|
||||
if(parsedExpression == null){
|
||||
lastOutputArea.setText(SYNTAX_ERR_STRING);
|
||||
return;
|
||||
}
|
||||
lastOutput = parsedExpression.reduce(reducer).toString();
|
||||
history += (history.length() == 0) ? "" : "\n\n";
|
||||
history += lastOutput;
|
||||
|
||||
historyModel.addEntry(new HistoryTableModel.HistoryEntry(inputField.getText(), parsedExpression, lastOutput));
|
||||
historyTable.invalidate();
|
||||
lastOutputArea.setText(lastOutput);
|
||||
inputField.setText(lastOutput);
|
||||
});
|
||||
historyTable.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
Point clickPoint = e.getPoint();
|
||||
if(e.getClickCount() == 2){
|
||||
int row = historyTable.rowAtPoint(clickPoint);
|
||||
int column = historyTable.columnAtPoint(clickPoint);
|
||||
String toCopy = historyTable.getValueAt(row, column).toString();
|
||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(toCopy), null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user