From 27cf6ce64b9c6c5f55337869252909e181e0dd90 Mon Sep 17 00:00:00 2001 From: rileyJones Date: Tue, 25 Jul 2017 14:52:57 -0700 Subject: [PATCH 01/10] Add GUI --- src/org/nwapw/abacus/window/Window.java | 63 +++++++++++++++++++++ src/org/nwapw/abacus/window/WindowTest.java | 24 ++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/org/nwapw/abacus/window/Window.java create mode 100644 src/org/nwapw/abacus/window/WindowTest.java diff --git a/src/org/nwapw/abacus/window/Window.java b/src/org/nwapw/abacus/window/Window.java new file mode 100644 index 0000000..5413d07 --- /dev/null +++ b/src/org/nwapw/abacus/window/Window.java @@ -0,0 +1,63 @@ +package org.nwapw.abacus.window; + +import javax.swing.*; +import java.awt.*; + +public class Window extends JFrame { + private String history; + private String lastOutput; + public Window(){ + super(); + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (UnsupportedLookAndFeelException e) { + e.printStackTrace(); + } + + //JFrame super= new JFrame(); + //ImageIcon check = new ImageIcon(".\\Window Images\\Untitled.png"); + String check = "Enter"; + JButton checkButton = new JButton(check); + JTextField inputBox = new JTextField(); + history=""; + JTextArea historyBox = new JTextArea(history); + JScrollPane scrollHistoryBox = new JScrollPane(historyBox); + JTextArea outputBox = new JTextArea(lastOutput); + JPanel output=new JPanel(); + output.setLayout(new BorderLayout()); + output.add(scrollHistoryBox); + output.add(outputBox, BorderLayout.PAGE_END); + JPanel input = new JPanel(); + input.setLayout(new BorderLayout()); + input.add(inputBox); + input.add(checkButton, BorderLayout.LINE_END); + super.add(output); + JPanel custom = new JPanel(); + JPanel numCustom = new JPanel(); + JPanel funCustom = new JPanel(); + custom.setLayout(new BorderLayout()); + numCustom.setLayout(new BorderLayout()); + funCustom.setLayout(new BorderLayout()); + JTextArea numLabel = new JTextArea("Number Type:"); + JTextArea funLabel = new JTextArea("Functions:"); + JComboBox numList = new JComboBox(); + JComboBox funList = new JComboBox(); + JButton funCheckButton = new JButton(check); + numCustom.add(numLabel); + numCustom.add(numList, BorderLayout.PAGE_END); + funCustom.add(funList); + funCustom.add(funCheckButton, BorderLayout.LINE_END); + funCustom.add(funLabel, BorderLayout.PAGE_START); + custom.add(numCustom); + custom.add(funCustom, BorderLayout.PAGE_END); + super.add(custom, BorderLayout.LINE_END); + super.add(input, BorderLayout.PAGE_END); + super.setVisible(true); + } +} diff --git a/src/org/nwapw/abacus/window/WindowTest.java b/src/org/nwapw/abacus/window/WindowTest.java new file mode 100644 index 0000000..377308c --- /dev/null +++ b/src/org/nwapw/abacus/window/WindowTest.java @@ -0,0 +1,24 @@ +package org.nwapw.abacus.window; + +import javax.swing.*; +import java.awt.Color; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.BorderLayout; +import java.util.Arrays; +public class WindowTest { + public static void main(String[] args){ + + + + + + + + + + new Window().setVisible(true); + + } +} From cc5d487386bca6fd0331b19290f29548ba48102e Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:11:11 -0700 Subject: [PATCH 02/10] Delete unused main method. --- src/org/nwapw/abacus/window/WindowTest.java | 24 --------------------- 1 file changed, 24 deletions(-) delete mode 100644 src/org/nwapw/abacus/window/WindowTest.java diff --git a/src/org/nwapw/abacus/window/WindowTest.java b/src/org/nwapw/abacus/window/WindowTest.java deleted file mode 100644 index 377308c..0000000 --- a/src/org/nwapw/abacus/window/WindowTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.nwapw.abacus.window; - -import javax.swing.*; -import java.awt.Color; -import java.awt.Frame; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.BorderLayout; -import java.util.Arrays; -public class WindowTest { - public static void main(String[] args){ - - - - - - - - - - new Window().setVisible(true); - - } -} From b93346ec372ce06dd38e97aa34f5ffda0b33bc01 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:11:36 -0700 Subject: [PATCH 03/10] Make the program actually create the UI. --- src/org/nwapw/abacus/Abacus.java | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/org/nwapw/abacus/Abacus.java b/src/org/nwapw/abacus/Abacus.java index 50b6bf7..74441d3 100644 --- a/src/org/nwapw/abacus/Abacus.java +++ b/src/org/nwapw/abacus/Abacus.java @@ -1,9 +1,29 @@ package org.nwapw.abacus; +import org.nwapw.abacus.window.Window; + +import javax.swing.*; + public class Abacus { + private Window mainUi; + + public Abacus(){ + init(); + } + + private void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException | IllegalAccessException e) { + e.printStackTrace(); + } + mainUi = new Window(); + mainUi.setVisible(true); + } + public static void main(String[] args){ - System.out.println("Hello world!"); + new Abacus(); } } From 7e7525cf3795c1c0426da86069832d603d76cc41 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:13:18 -0700 Subject: [PATCH 04/10] Tidy Window class with more explicit variable names and private vars. --- src/org/nwapw/abacus/window/Window.java | 121 ++++++++++++++---------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/src/org/nwapw/abacus/window/Window.java b/src/org/nwapw/abacus/window/Window.java index 5413d07..0b730b1 100644 --- a/src/org/nwapw/abacus/window/Window.java +++ b/src/org/nwapw/abacus/window/Window.java @@ -4,60 +4,77 @@ import javax.swing.*; import java.awt.*; public class Window extends JFrame { + private String history; private String lastOutput; - public Window(){ + + private JPanel outputPanel; + private JTextArea lastOutputArea; + private JTextArea historyArea; + private JScrollPane historyAreaScroll; + + private JPanel inputPanel; + private JTextField inputField; + private JButton inputEnterButton; + + private JPanel sidePanel; + private JPanel numberSystemPanel; + private JComboBox numberSystemList; + private JButton functionSelectButton; + private JPanel functionSelectPanel; + private JComboBox functionList; + + public Window() { super(); - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (UnsupportedLookAndFeelException e) { - e.printStackTrace(); - } - - //JFrame super= new JFrame(); - //ImageIcon check = new ImageIcon(".\\Window Images\\Untitled.png"); - String check = "Enter"; - JButton checkButton = new JButton(check); - JTextField inputBox = new JTextField(); - history=""; - JTextArea historyBox = new JTextArea(history); - JScrollPane scrollHistoryBox = new JScrollPane(historyBox); - JTextArea outputBox = new JTextArea(lastOutput); - JPanel output=new JPanel(); - output.setLayout(new BorderLayout()); - output.add(scrollHistoryBox); - output.add(outputBox, BorderLayout.PAGE_END); - JPanel input = new JPanel(); - input.setLayout(new BorderLayout()); - input.add(inputBox); - input.add(checkButton, BorderLayout.LINE_END); - super.add(output); - JPanel custom = new JPanel(); - JPanel numCustom = new JPanel(); - JPanel funCustom = new JPanel(); - custom.setLayout(new BorderLayout()); - numCustom.setLayout(new BorderLayout()); - funCustom.setLayout(new BorderLayout()); - JTextArea numLabel = new JTextArea("Number Type:"); - JTextArea funLabel = new JTextArea("Functions:"); - JComboBox numList = new JComboBox(); - JComboBox funList = new JComboBox(); - JButton funCheckButton = new JButton(check); - numCustom.add(numLabel); - numCustom.add(numList, BorderLayout.PAGE_END); - funCustom.add(funList); - funCustom.add(funCheckButton, BorderLayout.LINE_END); - funCustom.add(funLabel, BorderLayout.PAGE_START); - custom.add(numCustom); - custom.add(funCustom, BorderLayout.PAGE_END); - super.add(custom, BorderLayout.LINE_END); - super.add(input, BorderLayout.PAGE_END); - super.setVisible(true); + + + history = ""; + lastOutput = ""; + + setSize(640, 480); + + inputField = new JTextField(); + inputEnterButton = new JButton("Calculate"); + + inputPanel = new JPanel(); + inputPanel.setLayout(new BorderLayout()); + inputPanel.add(inputField); + inputPanel.add(inputEnterButton, BorderLayout.LINE_END); + + historyArea = new JTextArea(history); + historyAreaScroll = new JScrollPane(historyArea); + lastOutputArea = new JTextArea(lastOutput); + lastOutputArea.setEditable(false); + lastOutputArea.setText(":)"); + + outputPanel = new JPanel(); + outputPanel.setLayout(new BorderLayout()); + outputPanel.add(historyAreaScroll); + outputPanel.add(lastOutputArea, BorderLayout.PAGE_END); + + numberSystemList = new JComboBox<>(); + + numberSystemPanel = new JPanel(); + numberSystemPanel.setLayout(new BorderLayout()); + numberSystemPanel.add(new JLabel("Number Type:")); + numberSystemPanel.add(numberSystemList, BorderLayout.PAGE_END); + + functionList = new JComboBox<>(); + functionSelectButton = new JButton("Select"); + + functionSelectPanel = new JPanel(); + functionSelectPanel.setLayout(new BorderLayout()); + functionSelectPanel.add(new JLabel("Functions:")); + functionSelectPanel.add(functionList, BorderLayout.LINE_END); + functionSelectPanel.add(functionSelectButton, BorderLayout.LINE_END); + + sidePanel = new JPanel(); + sidePanel.setLayout(new BorderLayout()); + sidePanel.add(numberSystemPanel); + sidePanel.add(functionSelectPanel, BorderLayout.PAGE_END); + + add(outputPanel, BorderLayout.CENTER); + add(sidePanel, BorderLayout.EAST); + add(inputPanel, BorderLayout.SOUTH); } } From 3cf4f958b0dd85d859fc3fbf819fd904ebcd51af Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:50:30 -0700 Subject: [PATCH 05/10] Rename ExternalFunction --> Plugin, and implement plugin loading. --- .../nwapw/abacus/number/externalFunction.java | 28 ---------- src/org/nwapw/abacus/plugin/Plugin.java | 43 ++++++++++++++++ .../nwapw/abacus/plugin/PluginManager.java | 51 +++++++++++++++++++ 3 files changed, 94 insertions(+), 28 deletions(-) delete mode 100644 src/org/nwapw/abacus/number/externalFunction.java create mode 100644 src/org/nwapw/abacus/plugin/Plugin.java create mode 100644 src/org/nwapw/abacus/plugin/PluginManager.java diff --git a/src/org/nwapw/abacus/number/externalFunction.java b/src/org/nwapw/abacus/number/externalFunction.java deleted file mode 100644 index bcc4786..0000000 --- a/src/org/nwapw/abacus/number/externalFunction.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.nwapw.abacus.number; - -import java.util.HashMap; - -public abstract class externalFunction { - - private HashMap functions; - - public externalFunction(){ - functions=new HashMap<>(); - } - - public boolean hasFunction(Function x){ - return functions.containsKey(x); - } - public Function getFunction(String x){ - return functions.get(x); - } - public boolean registerFunction(String x, Function y){ - if(!functions.containsKey(x)) - return functions.put(x,y)==null; - return false; - } - public Function functionFor(String x){ - return null; - } - public abstract void load(); -} diff --git a/src/org/nwapw/abacus/plugin/Plugin.java b/src/org/nwapw/abacus/plugin/Plugin.java new file mode 100644 index 0000000..7f286db --- /dev/null +++ b/src/org/nwapw/abacus/plugin/Plugin.java @@ -0,0 +1,43 @@ +package org.nwapw.abacus.plugin; + +import org.nwapw.abacus.number.Function; + +import java.util.HashMap; + +public abstract class Plugin { + + private HashMap functions; + private PluginManager manager; + + private Plugin(){ } + + public Plugin(PluginManager manager) { + this.manager = manager; + functions = new HashMap<>(); + } + + public final boolean hasFunction(String functionName) { + return functions.containsKey(functionName); + } + + public final Function getFunction(String functionName) { + return functions.get(functionName); + } + + protected final boolean registerFunction(String name, Function toRegister) { + if(functionFor(name) == null){ + functions.put(name, toRegister); + return true; + } + return false; + } + + protected final Function functionFor(String name) { + Plugin ownerPlugin = manager.pluginForFunction(name); + if(ownerPlugin == null) return null; + return ownerPlugin.getFunction(name); + } + + public abstract void load(); + +} diff --git a/src/org/nwapw/abacus/plugin/PluginManager.java b/src/org/nwapw/abacus/plugin/PluginManager.java new file mode 100644 index 0000000..413c6e1 --- /dev/null +++ b/src/org/nwapw/abacus/plugin/PluginManager.java @@ -0,0 +1,51 @@ +package org.nwapw.abacus.plugin; + +import org.nwapw.abacus.number.Function; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; + +public class PluginManager { + + private ArrayList plugins; + private HashMap pluginsForFunctions; + + public PluginManager(){ + plugins = new ArrayList<>(); + pluginsForFunctions = new HashMap<>(); + } + + public Plugin pluginForFunction(String name){ + if(pluginsForFunctions.containsKey(name)) { + return pluginsForFunctions.get(name); + } + + Plugin foundPlugin = null; + for(Plugin plugin : plugins){ + if(plugin.hasFunction(name)) { + foundPlugin = plugin; + break; + } + } + pluginsForFunctions.put(name, foundPlugin); + + return foundPlugin; + } + + public void addInstantiated(Plugin plugin){ + plugin.load(); + pluginsForFunctions.clear(); + plugins.add(plugin); + } + + public void addClass(Class newClass){ + if(!Plugin.class.isAssignableFrom(newClass)) return; + try { + addInstantiated((Plugin) newClass.getConstructor(PluginManager.class).newInstance(this)); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + } + +} From 989ac80bf44c0312a100a735339ba962f1af74b8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:50:41 -0700 Subject: [PATCH 06/10] Move the standard functions into a standard plugin. --- .../StandardPlugin.java} | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) rename src/org/nwapw/abacus/{number/FunctionDatabase.java => plugin/StandardPlugin.java} (80%) mode change 100755 => 100644 diff --git a/src/org/nwapw/abacus/number/FunctionDatabase.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java old mode 100755 new mode 100644 similarity index 80% rename from src/org/nwapw/abacus/number/FunctionDatabase.java rename to src/org/nwapw/abacus/plugin/StandardPlugin.java index 4ec221d..c52b4ff --- a/src/org/nwapw/abacus/number/FunctionDatabase.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -1,13 +1,18 @@ -package org.nwapw.abacus.number; +package org.nwapw.abacus.plugin; -import java.util.HashMap; +import org.nwapw.abacus.number.Function; +import org.nwapw.abacus.number.NaiveNumber; +import org.nwapw.abacus.number.NumberInterface; -public class FunctionDatabase { +public class StandardPlugin extends Plugin { - private HashMap functions; + public StandardPlugin(PluginManager manager) { + super(manager); + } - private void registerDefault(){ - functions.put("+", new Function() { + @Override + public void load() { + registerFunction("+", new Function() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length >= 1; @@ -23,7 +28,7 @@ public class FunctionDatabase { } }); - functions.put("-", new Function() { + registerFunction("-", new Function() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2; @@ -35,7 +40,7 @@ public class FunctionDatabase { } }); - functions.put("*", new Function() { + registerFunction("*", new Function() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length >= 1; @@ -51,7 +56,7 @@ public class FunctionDatabase { } }); - functions.put("/", new Function() { + registerFunction("/", new Function() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2; @@ -63,7 +68,7 @@ public class FunctionDatabase { } }); - functions.put("!", new Function() { + registerFunction("!", new Function() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -82,13 +87,4 @@ public class FunctionDatabase { }); } - public FunctionDatabase(){ - functions = new HashMap<>(); - registerDefault(); - } - - public Function getFunction(String name){ - return functions.get(name); - } - } From 08a462b8f32e8dfc2b96922af10c7b03702a24e7 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:52:23 -0700 Subject: [PATCH 07/10] Add the plugin manager to the main. Abacus class. --- src/org/nwapw/abacus/Abacus.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/org/nwapw/abacus/Abacus.java b/src/org/nwapw/abacus/Abacus.java index 74441d3..7150c4e 100644 --- a/src/org/nwapw/abacus/Abacus.java +++ b/src/org/nwapw/abacus/Abacus.java @@ -1,5 +1,7 @@ package org.nwapw.abacus; +import org.nwapw.abacus.plugin.PluginManager; +import org.nwapw.abacus.plugin.StandardPlugin; import org.nwapw.abacus.window.Window; import javax.swing.*; @@ -7,6 +9,7 @@ import javax.swing.*; public class Abacus { private Window mainUi; + private PluginManager manager; public Abacus(){ init(); @@ -18,6 +21,8 @@ public class Abacus { } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException | IllegalAccessException e) { e.printStackTrace(); } + manager = new PluginManager(); + manager.addInstantiated(new StandardPlugin(manager)); mainUi = new Window(); mainUi.setVisible(true); } From 31b6adecd95600c705485fde4bd2044339de6726 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 21:57:14 -0700 Subject: [PATCH 08/10] Move function into its own package. --- src/org/nwapw/abacus/{number => function}/Function.java | 5 ++++- src/org/nwapw/abacus/plugin/Plugin.java | 2 +- src/org/nwapw/abacus/plugin/PluginManager.java | 2 -- src/org/nwapw/abacus/plugin/StandardPlugin.java | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) rename src/org/nwapw/abacus/{number => function}/Function.java (82%) diff --git a/src/org/nwapw/abacus/number/Function.java b/src/org/nwapw/abacus/function/Function.java similarity index 82% rename from src/org/nwapw/abacus/number/Function.java rename to src/org/nwapw/abacus/function/Function.java index 63f1ad4..bd5003d 100755 --- a/src/org/nwapw/abacus/number/Function.java +++ b/src/org/nwapw/abacus/function/Function.java @@ -1,4 +1,7 @@ -package org.nwapw.abacus.number; +package org.nwapw.abacus.function; + +import org.nwapw.abacus.number.NaiveNumber; +import org.nwapw.abacus.number.NumberInterface; import java.util.HashMap; diff --git a/src/org/nwapw/abacus/plugin/Plugin.java b/src/org/nwapw/abacus/plugin/Plugin.java index 7f286db..11e10e1 100644 --- a/src/org/nwapw/abacus/plugin/Plugin.java +++ b/src/org/nwapw/abacus/plugin/Plugin.java @@ -1,6 +1,6 @@ package org.nwapw.abacus.plugin; -import org.nwapw.abacus.number.Function; +import org.nwapw.abacus.function.Function; import java.util.HashMap; diff --git a/src/org/nwapw/abacus/plugin/PluginManager.java b/src/org/nwapw/abacus/plugin/PluginManager.java index 413c6e1..0e0d78a 100644 --- a/src/org/nwapw/abacus/plugin/PluginManager.java +++ b/src/org/nwapw/abacus/plugin/PluginManager.java @@ -1,7 +1,5 @@ package org.nwapw.abacus.plugin; -import org.nwapw.abacus.number.Function; - import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/org/nwapw/abacus/plugin/StandardPlugin.java b/src/org/nwapw/abacus/plugin/StandardPlugin.java index c52b4ff..4c6ccee 100644 --- a/src/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/src/org/nwapw/abacus/plugin/StandardPlugin.java @@ -1,6 +1,6 @@ package org.nwapw.abacus.plugin; -import org.nwapw.abacus.number.Function; +import org.nwapw.abacus.function.Function; import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; From ade4eb10354a03efd84c393d7452ec52b529ca54 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 22:08:12 -0700 Subject: [PATCH 09/10] Make some adjustments to the UI. --- src/org/nwapw/abacus/window/Window.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/org/nwapw/abacus/window/Window.java b/src/org/nwapw/abacus/window/Window.java index 0b730b1..61575b7 100644 --- a/src/org/nwapw/abacus/window/Window.java +++ b/src/org/nwapw/abacus/window/Window.java @@ -38,8 +38,8 @@ public class Window extends JFrame { inputPanel = new JPanel(); inputPanel.setLayout(new BorderLayout()); - inputPanel.add(inputField); - inputPanel.add(inputEnterButton, BorderLayout.LINE_END); + inputPanel.add(inputField, BorderLayout.CENTER); + inputPanel.add(inputEnterButton, BorderLayout.EAST); historyArea = new JTextArea(history); historyAreaScroll = new JScrollPane(historyArea); @@ -49,29 +49,29 @@ public class Window extends JFrame { outputPanel = new JPanel(); outputPanel.setLayout(new BorderLayout()); - outputPanel.add(historyAreaScroll); - outputPanel.add(lastOutputArea, BorderLayout.PAGE_END); + outputPanel.add(historyAreaScroll, BorderLayout.CENTER); + outputPanel.add(lastOutputArea, BorderLayout.SOUTH); numberSystemList = new JComboBox<>(); numberSystemPanel = new JPanel(); numberSystemPanel.setLayout(new BorderLayout()); - numberSystemPanel.add(new JLabel("Number Type:")); - numberSystemPanel.add(numberSystemList, BorderLayout.PAGE_END); + numberSystemPanel.add(new JLabel("Number Type:"), BorderLayout.NORTH); + numberSystemPanel.add(numberSystemList, BorderLayout.CENTER); functionList = new JComboBox<>(); functionSelectButton = new JButton("Select"); functionSelectPanel = new JPanel(); functionSelectPanel.setLayout(new BorderLayout()); - functionSelectPanel.add(new JLabel("Functions:")); - functionSelectPanel.add(functionList, BorderLayout.LINE_END); - functionSelectPanel.add(functionSelectButton, BorderLayout.LINE_END); + functionSelectPanel.add(new JLabel("Functions:"), BorderLayout.NORTH); + functionSelectPanel.add(functionList, BorderLayout.CENTER); + functionSelectPanel.add(functionSelectButton, BorderLayout.SOUTH); sidePanel = new JPanel(); sidePanel.setLayout(new BorderLayout()); - sidePanel.add(numberSystemPanel); - sidePanel.add(functionSelectPanel, BorderLayout.PAGE_END); + sidePanel.add(numberSystemPanel, BorderLayout.NORTH); + sidePanel.add(functionSelectPanel, BorderLayout.SOUTH); add(outputPanel, BorderLayout.CENTER); add(sidePanel, BorderLayout.EAST); From c19ae3b071e6c49ec8ac6ee790679dcc9cbf30b8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 25 Jul 2017 22:47:48 -0700 Subject: [PATCH 10/10] Add a lot of comments. More to come. --- src/org/nwapw/abacus/function/Function.java | 24 +++++++ src/org/nwapw/abacus/lexing/Lexer.java | 30 +++++++++ .../nwapw/abacus/lexing/pattern/AnyNode.java | 4 ++ .../nwapw/abacus/lexing/pattern/EndNode.java | 15 +++++ .../nwapw/abacus/lexing/pattern/LinkNode.java | 4 ++ .../nwapw/abacus/lexing/pattern/Match.java | 31 +++++++++ .../nwapw/abacus/lexing/pattern/Pattern.java | 66 +++++++++++++++++++ .../abacus/lexing/pattern/PatternChain.java | 35 ++++++++++ .../abacus/lexing/pattern/PatternNode.java | 32 +++++++++ .../abacus/lexing/pattern/RangeNode.java | 15 +++++ .../abacus/lexing/pattern/ValueNode.java | 11 ++++ src/org/nwapw/abacus/number/NaiveNumber.java | 16 +++++ .../nwapw/abacus/number/NumberInterface.java | 60 +++++++++++++++++ 13 files changed, 343 insertions(+) diff --git a/src/org/nwapw/abacus/function/Function.java b/src/org/nwapw/abacus/function/Function.java index bd5003d..103c3f4 100755 --- a/src/org/nwapw/abacus/function/Function.java +++ b/src/org/nwapw/abacus/function/Function.java @@ -5,16 +5,40 @@ import org.nwapw.abacus.number.NumberInterface; import java.util.HashMap; +/** + * A function that operates on one or more + * inputs and returns a single number. + */ public abstract class Function { + /** + * A map to correctly promote different number implementations to each other. + */ private static final HashMap, Integer> priorityMap = new HashMap, Integer>() {{ put(NaiveNumber.class, 0); }}; + /** + * Checks whether the given params will work for the given function. + * @param params the given params + * @return true if the params can be used with this function. + */ protected abstract boolean matchesParams(NumberInterface[] params); + + /** + * Internal apply implementation, which already receives appropriately promoted + * parameters that have bee run through matchesParams + * @param params the promoted parameters. + * @return the return value of the function. + */ protected abstract NumberInterface applyInternal(NumberInterface[] params); + /** + * Function to check, promote arguments and run the function. + * @param params the raw input parameters. + * @return the return value of the function, or null if an error occurred. + */ public NumberInterface apply(NumberInterface...params) { if(!matchesParams(params)) return null; return applyInternal(params); diff --git a/src/org/nwapw/abacus/lexing/Lexer.java b/src/org/nwapw/abacus/lexing/Lexer.java index 94457a1..2813061 100644 --- a/src/org/nwapw/abacus/lexing/Lexer.java +++ b/src/org/nwapw/abacus/lexing/Lexer.java @@ -9,19 +9,42 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.HashSet; +/** + * A lexer that can generate tokens of a given type given a list of regular expressions + * to operate on. + * @param the type used to identify which match belongs to which pattern. + */ public class Lexer { + /** + * The registered patterns. + */ private ArrayList> patterns; + /** + * Creates a new lexer with no registered patterns. + */ public Lexer(){ patterns = new ArrayList<>(); } + /** + * Registers a single pattern. + * @param pattern the pattern regex + * @param id the ID by which to identify the pattern. + */ public void register(String pattern, T id){ Pattern compiledPattern = new Pattern<>(pattern, id); if(compiledPattern.getHead() != null) patterns.add(compiledPattern); } + /** + * Reads one token from the given string. + * @param from the string to read from + * @param startAt the index to start at + * @param compare the comparator used to sort tokens by their ID. + * @return the best match. + */ public Match lexOne(String from, int startAt, Comparator compare){ ArrayList> matches = new ArrayList<>(); HashSet> currentSet = new HashSet<>(); @@ -53,6 +76,13 @@ public class Lexer { return matches.isEmpty() ? null : matches.get(matches.size() - 1); } + /** + * Reads all tokens from a string. + * @param from the string to start from. + * @param startAt the index to start at. + * @param compare the comparator used to sort matches by their IDs. + * @return the resulting list of matches, in order, or null on error. + */ public ArrayList> lexAll(String from, int startAt, Comparator compare){ int index = startAt; ArrayList> matches = new ArrayList<>(); diff --git a/src/org/nwapw/abacus/lexing/pattern/AnyNode.java b/src/org/nwapw/abacus/lexing/pattern/AnyNode.java index 1cfa635..5b75e51 100644 --- a/src/org/nwapw/abacus/lexing/pattern/AnyNode.java +++ b/src/org/nwapw/abacus/lexing/pattern/AnyNode.java @@ -1,5 +1,9 @@ package org.nwapw.abacus.lexing.pattern; +/** + * A pattern node that matches any character. + * @param the type that's used to tell which pattern this node belongs to. + */ public class AnyNode extends PatternNode { @Override diff --git a/src/org/nwapw/abacus/lexing/pattern/EndNode.java b/src/org/nwapw/abacus/lexing/pattern/EndNode.java index d8e621d..81be4cd 100644 --- a/src/org/nwapw/abacus/lexing/pattern/EndNode.java +++ b/src/org/nwapw/abacus/lexing/pattern/EndNode.java @@ -1,13 +1,28 @@ package org.nwapw.abacus.lexing.pattern; +/** + * A node that represents a successful match. + * @param the type that's used to tell which pattern this node belongs to. + */ public class EndNode extends PatternNode { + /** + * The ID of the pattenr that has been matched. + */ private T patternId; + /** + * Creates a new end node with the given ID. + * @param patternId the pattern ID. + */ public EndNode(T patternId){ this.patternId = patternId; } + /** + * Gets the pattern ID. + * @return the pattern ID. + */ public T getPatternId(){ return patternId; } diff --git a/src/org/nwapw/abacus/lexing/pattern/LinkNode.java b/src/org/nwapw/abacus/lexing/pattern/LinkNode.java index 460c418..7c85c0f 100644 --- a/src/org/nwapw/abacus/lexing/pattern/LinkNode.java +++ b/src/org/nwapw/abacus/lexing/pattern/LinkNode.java @@ -3,6 +3,10 @@ package org.nwapw.abacus.lexing.pattern; import java.util.ArrayList; import java.util.Collection; +/** + * A node that is used as structural glue in pattern compilation. + * @param the type that's used to tell which pattern this node belongs to. + */ public class LinkNode extends PatternNode { @Override diff --git a/src/org/nwapw/abacus/lexing/pattern/Match.java b/src/org/nwapw/abacus/lexing/pattern/Match.java index 06e0b27..15ee33d 100644 --- a/src/org/nwapw/abacus/lexing/pattern/Match.java +++ b/src/org/nwapw/abacus/lexing/pattern/Match.java @@ -1,25 +1,56 @@ package org.nwapw.abacus.lexing.pattern; +/** + * A match that has been generated by the lexer. + * @param the type used to represent the ID of the pattern this match belongs to. + */ public class Match { + /** + * The bottom range of the string, inclusive. + */ private int from; + /** + * The top range of the string, exclusive. + */ private int to; + /** + * The pattern type this match matched. + */ private T type; + /** + * Creates a new match with the given parameters. + * @param from the bottom range of the string. + * @param to the top range of the string. + * @param type the type of the match. + */ public Match(int from, int to, T type){ this.from = from; this.to = to; this.type = type; } + /** + * Gets the bottom range bound of the string. + * @return the bottom range bound of the string. + */ public int getFrom() { return from; } + /** + * Gets the top range bound of the string. + * @return the top range bound of the string. + */ public int getTo() { return to; } + /** + * Gets the pattern type of the node. + * @return the ID of the pattern that this match matched. + */ public T getType() { return type; } diff --git a/src/org/nwapw/abacus/lexing/pattern/Pattern.java b/src/org/nwapw/abacus/lexing/pattern/Pattern.java index 4d40d77..2057a8c 100644 --- a/src/org/nwapw/abacus/lexing/pattern/Pattern.java +++ b/src/org/nwapw/abacus/lexing/pattern/Pattern.java @@ -5,13 +5,33 @@ import java.util.HashMap; import java.util.Stack; import java.util.function.Function; +/** + * A pattern that can be compiled from a string and used in lexing. + * @param the type that is used to identify and sort this pattern. + */ public class Pattern { + /** + * The ID of this pattern. + */ private T id; + /** + * The head of this pattern. + */ private PatternNode head; + /** + * The source string of this pattern. + */ private String source; + /** + * The index at which the compilation has stopped. + */ private int index; + /** + * A map of regex operator to functions that modify a PatternChain + * with the appropriate operation. + */ private HashMap, PatternChain>> operations = new HashMap, PatternChain>>() {{ put('+', Pattern.this::transformPlus); @@ -19,11 +39,23 @@ public class Pattern { put('?', Pattern.this::transformQuestion); }}; + /** + * A regex operator function that turns the chain + * into a one-or-more chain. + * @param chain the chain to transform. + * @return the modified chain. + */ private PatternChain transformPlus(PatternChain chain){ chain.tail.outputStates.add(chain.head); return chain; } + /** + * A regex operator function that turns the chain + * into a zero-or-more chain. + * @param chain the chain to transform. + * @return the modified chain. + */ private PatternChain transformStar(PatternChain chain){ LinkNode newTail = new LinkNode<>(); LinkNode newHead = new LinkNode<>(); @@ -36,6 +68,12 @@ public class Pattern { return chain; } + /** + * A regex operator function that turns the chain + * into a zero-or-one chain. + * @param chain the chain to transform. + * @return the modified chain. + */ private PatternChain transformQuestion(PatternChain chain){ LinkNode newTail = new LinkNode<>(); LinkNode newHead = new LinkNode<>(); @@ -47,6 +85,11 @@ public class Pattern { return chain; } + /** + * Combines a collection of chains into one OR chain. + * @param collection the collection of chains to combine. + * @return the resulting OR chain. + */ private PatternChain combineChains(Collection> collection){ LinkNode head = new LinkNode<>(); LinkNode tail = new LinkNode<>(); @@ -58,6 +101,10 @@ public class Pattern { return newChain; } + /** + * Parses a single value from the input into a chain. + * @return the resulting chain, or null on error. + */ private PatternChain parseValue(){ if(index >= source.length()) return null; if(source.charAt(index) == '\\'){ @@ -66,6 +113,10 @@ public class Pattern { return new PatternChain<>(new ValueNode<>(source.charAt(index++))); } + /** + * Parses a [] range from the input into a chain. + * @return the resulting chain, or null on error. + */ private PatternChain parseOr(){ Stack> orStack = new Stack<>(); index++; @@ -88,6 +139,12 @@ public class Pattern { return (orStack.size() == 1) ? orStack.pop() : combineChains(orStack); } + /** + * Parses a repeatable segment from the input into a chain + * @param isSubsegment whether the segment is a sub-expression "()", and therefore + * whether to expect a closing brace. + * @return the resulting chain, or null on error. + */ private PatternChain parseSegment(boolean isSubsegment){ if(index >= source.length() || ((source.charAt(index) != '(') && isSubsegment)) return null; if(isSubsegment) index++; @@ -152,6 +209,11 @@ public class Pattern { return fullChain; } + /** + * Creates / compiles a new pattern with the given id from the given string. + * @param from the string to compile a pattern from. + * @param id the ID to use. + */ public Pattern(String from, T id){ this.id = id; index = 0; @@ -166,6 +228,10 @@ public class Pattern { } } + /** + * Gets the head PatternNode, for use in matching + * @return the pattern node. + */ public PatternNode getHead() { return head; } diff --git a/src/org/nwapw/abacus/lexing/pattern/PatternChain.java b/src/org/nwapw/abacus/lexing/pattern/PatternChain.java index aad9be5..a6edb21 100644 --- a/src/org/nwapw/abacus/lexing/pattern/PatternChain.java +++ b/src/org/nwapw/abacus/lexing/pattern/PatternChain.java @@ -1,23 +1,52 @@ package org.nwapw.abacus.lexing.pattern; +/** + * A chain of nodes that can be treated as a single unit. + * Used during pattern compilation. + * @param the type used to identify which pattern has been matched. + */ public class PatternChain { + /** + * The head node of the chain. + */ public PatternNode head; + /** + * The tail node of the chain. + */ public PatternNode tail; + /** + * Creates a new chain with the given start and end. + * @param head the start of the chain. + * @param tail the end of the chain. + */ public PatternChain(PatternNode head, PatternNode tail){ this.head = head; this.tail = tail; } + /** + * Creates a chain that starts and ends with the same node. + * @param node the node to use. + */ public PatternChain(PatternNode node){ this(node, node); } + /** + * Creates an empty chain. + */ public PatternChain(){ this(null); } + /** + * Appends the other chain to this one. This modifies + * the nodes, as well. + * If this chain is empty, it is set to the other. + * @param other the other chain to append. + */ public void append(PatternChain other){ if(other.head == null || tail == null) { this.head = other.head; @@ -28,6 +57,12 @@ public class PatternChain { } } + /** + * Appends a single node to this chain. This modifies + * the nodes, as well. + * If this chain is empty, it is set to the node. + * @param node the node to append to this chain. + */ public void append(PatternNode node){ if(tail == null){ head = tail = node; diff --git a/src/org/nwapw/abacus/lexing/pattern/PatternNode.java b/src/org/nwapw/abacus/lexing/pattern/PatternNode.java index 4c0908a..51208db 100644 --- a/src/org/nwapw/abacus/lexing/pattern/PatternNode.java +++ b/src/org/nwapw/abacus/lexing/pattern/PatternNode.java @@ -4,26 +4,58 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +/** + * A base class for a pattern node. Provides all functions + * necessary for matching, and is constructed by a Pattern instance + * from a string. + * @param the type that's used to tell which pattern this node belongs to. + */ public class PatternNode { + /** + * The set of states to which the lexer should continue + * should this node be correctly matched. + */ protected HashSet> outputStates; + /** + * Creates a new pattern node. + */ public PatternNode(){ outputStates = new HashSet<>(); } + /** + * Determines whether the current input character can + * be matched by this node. + * @param other the character being matched. + * @return true if the character can be matched, false otherwise. + */ public boolean matches(char other){ return false; } + /** + * If this node can be used as part of a range, returns that value. + * @return a NULL terminator if this character cannot be converted + * into a range bound, or the appropriate range bound if it can. + */ public char range(){ return '\0'; } + /** + * Adds this node in a collection of other nodes. + * @param into the collection to add into. + */ public void addInto(Collection> into){ into.add(this); } + /** + * Adds the node's children into a collection of other nodes. + * @param into the collection to add into. + */ public void addOutputsInto(Collection> into){ outputStates.forEach(e -> e.addInto(into)); } diff --git a/src/org/nwapw/abacus/lexing/pattern/RangeNode.java b/src/org/nwapw/abacus/lexing/pattern/RangeNode.java index 4ff9e5b..1eae44c 100644 --- a/src/org/nwapw/abacus/lexing/pattern/RangeNode.java +++ b/src/org/nwapw/abacus/lexing/pattern/RangeNode.java @@ -1,10 +1,25 @@ package org.nwapw.abacus.lexing.pattern; +/** + * A node that matches a range of characters. + * @param the type that's used to tell which pattern this node belongs to. + */ public class RangeNode extends PatternNode { + /** + * The bottom bound of the range, inclusive. + */ private char from; + /** + * The top bound of the range, inclusive. + */ private char to; + /** + * Creates a new range node from the given range. + * @param from the bottom bound of the range. + * @param to the top bound of hte range. + */ public RangeNode(char from, char to){ this.from = from; this.to = to; diff --git a/src/org/nwapw/abacus/lexing/pattern/ValueNode.java b/src/org/nwapw/abacus/lexing/pattern/ValueNode.java index 855f805..b3268ac 100644 --- a/src/org/nwapw/abacus/lexing/pattern/ValueNode.java +++ b/src/org/nwapw/abacus/lexing/pattern/ValueNode.java @@ -1,9 +1,20 @@ package org.nwapw.abacus.lexing.pattern; +/** + * A node that matches a single value. + * @param the type that's used to tell which pattern this node belongs to. + */ public class ValueNode extends PatternNode { + /** + * The value this node matches. + */ private char value; + /** + * Creates a new node that matches the given character. + * @param value + */ public ValueNode(char value){ this.value = value; } diff --git a/src/org/nwapw/abacus/number/NaiveNumber.java b/src/org/nwapw/abacus/number/NaiveNumber.java index 6ad43f1..585f7f1 100755 --- a/src/org/nwapw/abacus/number/NaiveNumber.java +++ b/src/org/nwapw/abacus/number/NaiveNumber.java @@ -1,14 +1,30 @@ package org.nwapw.abacus.number; +/** + * An implementation of NumberInterface using a double. + */ public class NaiveNumber implements NumberInterface { + /** + * The value of this number. + */ private double value; + /** + * Creates a new NaiveNumber with the given value. + * @param value the value to use. + */ public NaiveNumber(double value) { this.value = value; } + /** + * The number zero. + */ public static final NaiveNumber ZERO = new NaiveNumber(0); + /** + * The number one. + */ public static final NaiveNumber ONE = new NaiveNumber(1); @Override diff --git a/src/org/nwapw/abacus/number/NumberInterface.java b/src/org/nwapw/abacus/number/NumberInterface.java index e9cf59b..85f2214 100755 --- a/src/org/nwapw/abacus/number/NumberInterface.java +++ b/src/org/nwapw/abacus/number/NumberInterface.java @@ -1,17 +1,77 @@ package org.nwapw.abacus.number; +/** + * An interface used to represent a number. + */ public interface NumberInterface { + /** + * The precision to which this number operates. + * @return the precision. + */ int precision(); + + /** + * Multiplies this number by another, returning + * a new number instance. + * @param multiplier the multiplier + * @return the result of the multiplication. + */ NumberInterface multiply(NumberInterface multiplier); + /** + * Divides this number by another, returning + * a new number instance. + * @param divisor the divisor + * @return the result of the division. + */ NumberInterface divide(NumberInterface divisor); + /** + * Adds this number to another, returning + * a new number instance. + * @param summand the summand + * @return the result of the summation. + */ NumberInterface add(NumberInterface summand); + /** + * Subtracts another number from this number, + * a new number instance. + * @param subtrahend the subtrahend. + * @return the result of the subtraction. + */ NumberInterface subtract(NumberInterface subtrahend); + + /** + * Returns a new instance of this number with + * the sign flipped. + * @return the new instance. + */ NumberInterface negate(); + + /** + * Raises this number to an integer power. + * @param exponent + * @return + */ NumberInterface intPow(int exponent); + + /** + * Compares this number to another. + * @param number the number to compare to. + * @return same as Integer.compare(); + */ int compareTo(NumberInterface number); + + /** + * Same as Math.signum(). + * @return 1 if this number is positive, -1 if this number is negative, 0 if this number is 0. + */ int signum(); + /** + * Promotes this class to another number class. + * @param toClass the class to promote to. + * @return the resulting new instance. + */ NumberInterface promoteTo(Class toClass); }