diff --git a/src/org/nwapw/abacus/Abacus.java b/src/org/nwapw/abacus/Abacus.java index 50b6bf7..7150c4e 100644 --- a/src/org/nwapw/abacus/Abacus.java +++ b/src/org/nwapw/abacus/Abacus.java @@ -1,9 +1,34 @@ 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.*; + public class Abacus { + private Window mainUi; + private PluginManager manager; + + public Abacus(){ + init(); + } + + private void init() { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | UnsupportedLookAndFeelException | IllegalAccessException e) { + e.printStackTrace(); + } + manager = new PluginManager(); + manager.addInstantiated(new StandardPlugin(manager)); + mainUi = new Window(); + mainUi.setVisible(true); + } + public static void main(String[] args){ - System.out.println("Hello world!"); + new Abacus(); } } diff --git a/src/org/nwapw/abacus/function/Function.java b/src/org/nwapw/abacus/function/Function.java new file mode 100755 index 0000000..103c3f4 --- /dev/null +++ b/src/org/nwapw/abacus/function/Function.java @@ -0,0 +1,47 @@ +package org.nwapw.abacus.function; + +import org.nwapw.abacus.number.NaiveNumber; +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/Function.java b/src/org/nwapw/abacus/number/Function.java deleted file mode 100755 index 63f1ad4..0000000 --- a/src/org/nwapw/abacus/number/Function.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.nwapw.abacus.number; - -import java.util.HashMap; - -public abstract class Function { - - private static final HashMap, Integer> priorityMap = - new HashMap, Integer>() {{ - put(NaiveNumber.class, 0); - }}; - - protected abstract boolean matchesParams(NumberInterface[] params); - protected abstract NumberInterface applyInternal(NumberInterface[] params); - - public NumberInterface apply(NumberInterface...params) { - if(!matchesParams(params)) return null; - return applyInternal(params); - } - -} diff --git a/src/org/nwapw/abacus/number/NaiveNumber.java b/src/org/nwapw/abacus/number/NaiveNumber.java index 2465007..93c501b 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); } 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..11e10e1 --- /dev/null +++ b/src/org/nwapw/abacus/plugin/Plugin.java @@ -0,0 +1,43 @@ +package org.nwapw.abacus.plugin; + +import org.nwapw.abacus.function.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..0e0d78a --- /dev/null +++ b/src/org/nwapw/abacus/plugin/PluginManager.java @@ -0,0 +1,49 @@ +package org.nwapw.abacus.plugin; + +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(); + } + } + +} 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..4c6ccee --- 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.function.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); - } - } diff --git a/src/org/nwapw/abacus/window/Window.java b/src/org/nwapw/abacus/window/Window.java new file mode 100644 index 0000000..61575b7 --- /dev/null +++ b/src/org/nwapw/abacus/window/Window.java @@ -0,0 +1,80 @@ +package org.nwapw.abacus.window; + +import javax.swing.*; +import java.awt.*; + +public class Window extends JFrame { + + private String history; + private String lastOutput; + + 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(); + + + history = ""; + lastOutput = ""; + + setSize(640, 480); + + inputField = new JTextField(); + inputEnterButton = new JButton("Calculate"); + + 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); + lastOutputArea = new JTextArea(lastOutput); + lastOutputArea.setEditable(false); + lastOutputArea.setText(":)"); + + outputPanel = new JPanel(); + outputPanel.setLayout(new BorderLayout()); + 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:"), 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:"), BorderLayout.NORTH); + functionSelectPanel.add(functionList, BorderLayout.CENTER); + functionSelectPanel.add(functionSelectButton, BorderLayout.SOUTH); + + sidePanel = new JPanel(); + sidePanel.setLayout(new BorderLayout()); + sidePanel.add(numberSystemPanel, BorderLayout.NORTH); + sidePanel.add(functionSelectPanel, BorderLayout.SOUTH); + + add(outputPanel, BorderLayout.CENTER); + add(sidePanel, BorderLayout.EAST); + add(inputPanel, BorderLayout.SOUTH); + } +}