mirror of
https://github.com/DanilaFe/abacus
synced 2024-12-22 15:30:09 -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
|
* Rembulan(5.3) - https://github.com/mjanicek/rembulan
|
||||||
* LuaJava - https://github.com/jasonsantos/luajava
|
* LuaJava - https://github.com/jasonsantos/luajava
|
||||||
* jnlua - https://code.google.com/archive/p/jnlua/
|
* 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 = new PluginManager();
|
||||||
manager.addInstantiated(new StandardPlugin(manager));
|
manager.addInstantiated(new StandardPlugin(manager));
|
||||||
mainUi = new Window();
|
mainUi = new Window(manager);
|
||||||
mainUi.setVisible(true);
|
mainUi.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,11 +87,12 @@ public class Lexer<T> {
|
||||||
int index = startAt;
|
int index = startAt;
|
||||||
ArrayList<Match<T>> matches = new ArrayList<>();
|
ArrayList<Match<T>> matches = new ArrayList<>();
|
||||||
Match<T> lastMatch = null;
|
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;
|
if(lastMatch.getTo() == lastMatch.getFrom()) return null;
|
||||||
matches.add(lastMatch);
|
matches.add(lastMatch);
|
||||||
index += lastMatch.getTo() - lastMatch.getFrom();
|
index += lastMatch.getTo() - lastMatch.getFrom();
|
||||||
}
|
}
|
||||||
|
if(lastMatch == null) return null;
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,4 +44,9 @@ public class NumberNode extends TreeNode {
|
||||||
public NumberInterface getNumber() {
|
public NumberInterface getNumber() {
|
||||||
return number;
|
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 TreeNode right;
|
||||||
|
|
||||||
|
private OpNode() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new operation node with the given operation
|
* Creates a new operation node with the given operation
|
||||||
* and no child nodes.
|
* and no child nodes.
|
||||||
|
@ -79,4 +81,11 @@ public class OpNode extends TreeNode {
|
||||||
public void setRight(TreeNode right) {
|
public void setRight(TreeNode right) {
|
||||||
this.right = 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.
|
* The lexer used to lex tokens.
|
||||||
*/
|
*/
|
||||||
private static Lexer<TokenType> lexer = new Lexer<TokenType>(){{
|
private static Lexer<TokenType> lexer = new Lexer<TokenType>(){{
|
||||||
register(".", TokenType.ANY);
|
|
||||||
register("\\+|-|\\*|/|^", TokenType.OP);
|
register("\\+|-|\\*|/|^", TokenType.OP);
|
||||||
register("[0-9]+(\\.[0-9]+)?", TokenType.NUM);
|
register("[0-9]+(\\.[0-9]+)?", TokenType.NUM);
|
||||||
register("[a-zA-Z]+", TokenType.WORD);
|
register("[a-zA-Z]+", TokenType.WORD);
|
||||||
|
@ -130,11 +129,15 @@ public abstract class TreeNode {
|
||||||
* @return the resulting tree.
|
* @return the resulting tree.
|
||||||
*/
|
*/
|
||||||
public static TreeNode fromString(String string){
|
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;
|
if(matches == null) return null;
|
||||||
|
|
||||||
Collections.reverse(matches);
|
Collections.reverse(matches);
|
||||||
return fromStringRecursive(string, 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;
|
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 javax.swing.*;
|
||||||
import java.awt.*;
|
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.
|
* The main UI window for the calculator.
|
||||||
*/
|
*/
|
||||||
public class Window extends JFrame {
|
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.
|
* A collection of outputs from the calculator.
|
||||||
*/
|
*/
|
||||||
|
@ -26,13 +48,17 @@ public class Window extends JFrame {
|
||||||
*/
|
*/
|
||||||
private JTextArea lastOutputArea;
|
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.
|
* The scroll pane for the history area.
|
||||||
*/
|
*/
|
||||||
private JScrollPane historyAreaScroll;
|
private JScrollPane historyScroll;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The panel where the input occurs.
|
* The panel where the input occurs.
|
||||||
|
@ -74,9 +100,21 @@ public class Window extends JFrame {
|
||||||
*/
|
*/
|
||||||
private JButton functionSelectButton;
|
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 = "";
|
history = "";
|
||||||
lastOutput = "";
|
lastOutput = "";
|
||||||
|
@ -84,37 +122,37 @@ public class Window extends JFrame {
|
||||||
setSize(640, 480);
|
setSize(640, 480);
|
||||||
|
|
||||||
inputField = new JTextField();
|
inputField = new JTextField();
|
||||||
inputEnterButton = new JButton("Calculate");
|
inputEnterButton = new JButton(CALC_STRING);
|
||||||
|
|
||||||
inputPanel = new JPanel();
|
inputPanel = new JPanel();
|
||||||
inputPanel.setLayout(new BorderLayout());
|
inputPanel.setLayout(new BorderLayout());
|
||||||
inputPanel.add(inputField, BorderLayout.CENTER);
|
inputPanel.add(inputField, BorderLayout.CENTER);
|
||||||
inputPanel.add(inputEnterButton, BorderLayout.EAST);
|
inputPanel.add(inputEnterButton, BorderLayout.EAST);
|
||||||
|
|
||||||
historyArea = new JTextArea(history);
|
historyModel = new HistoryTableModel();
|
||||||
historyAreaScroll = new JScrollPane(historyArea);
|
historyTable = new JTable(historyModel);
|
||||||
|
historyScroll = new JScrollPane(historyTable);
|
||||||
lastOutputArea = new JTextArea(lastOutput);
|
lastOutputArea = new JTextArea(lastOutput);
|
||||||
lastOutputArea.setEditable(false);
|
lastOutputArea.setEditable(false);
|
||||||
lastOutputArea.setText(":)");
|
|
||||||
|
|
||||||
outputPanel = new JPanel();
|
outputPanel = new JPanel();
|
||||||
outputPanel.setLayout(new BorderLayout());
|
outputPanel.setLayout(new BorderLayout());
|
||||||
outputPanel.add(historyAreaScroll, BorderLayout.CENTER);
|
outputPanel.add(historyScroll, BorderLayout.CENTER);
|
||||||
outputPanel.add(lastOutputArea, BorderLayout.SOUTH);
|
outputPanel.add(lastOutputArea, BorderLayout.SOUTH);
|
||||||
|
|
||||||
numberSystemList = new JComboBox<>();
|
numberSystemList = new JComboBox<>();
|
||||||
|
|
||||||
numberSystemPanel = new JPanel();
|
numberSystemPanel = new JPanel();
|
||||||
numberSystemPanel.setLayout(new BorderLayout());
|
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);
|
numberSystemPanel.add(numberSystemList, BorderLayout.CENTER);
|
||||||
|
|
||||||
functionList = new JComboBox<>();
|
functionList = new JComboBox<>();
|
||||||
functionSelectButton = new JButton("Select");
|
functionSelectButton = new JButton(SELECT_STRING);
|
||||||
|
|
||||||
functionSelectPanel = new JPanel();
|
functionSelectPanel = new JPanel();
|
||||||
functionSelectPanel.setLayout(new BorderLayout());
|
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(functionList, BorderLayout.CENTER);
|
||||||
functionSelectPanel.add(functionSelectButton, BorderLayout.SOUTH);
|
functionSelectPanel.add(functionSelectButton, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
@ -126,5 +164,33 @@ public class Window extends JFrame {
|
||||||
add(outputPanel, BorderLayout.CENTER);
|
add(outputPanel, BorderLayout.CENTER);
|
||||||
add(sidePanel, BorderLayout.EAST);
|
add(sidePanel, BorderLayout.EAST);
|
||||||
add(inputPanel, BorderLayout.SOUTH);
|
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